Vue로 PWA 개발

25. mylog 날짜별 조회수

그랜파 개발자 2024. 10. 24. 14:53

조회수에 대해 ‘/views/{postId}/users/{userId or anonymousId}’ 구조에 lastViewed 항목 즉 마지막 조회날짜 하나만 가진다면, 날짜별 조회수를 구할 수 없습니다. 사용자가 조회한 각 날짜 정보를 가져야 날짜별로 조회수를 구할 수 있습니다.

ChatGPT에게 물었습니다.

lastViewed를 배열로 해서 조회 시간을 계속 추가하고 싶어

 

ChatGPT

lastViewed 필드를 배열로 만들어 사용자가 해당 글을 조회할 때마다 조회 시간을 배열에 추가할 수 있습니다. Firestore는 배열 데이터를 지원하며, 배열에 항목을 추가하거나 업데이트할 수 있는 기능을 제공합니다. 이를 사용하면 사용자가 글을 조회할 때마다 조회 시간을 배열에 계속 추가할 수 있습니다.

Firestore에서 배열 업데이트 방법

Firestore에서 배열 필드를 업데이트할 때는 arrayUnion이라는 메서드를 사용합니다. arrayUnion은 해당 배열에 이미 존재하지 않는 값만 추가하며, 값이 중복되지 않도록 관리합니다. 이를 활용해 사용자가 글을 조회할 때마다 조회 시간을 배열로 저장할 수 있습니다.

구현 방법

  1. 배열 필드 생성: lastViewed 필드를 배열로 만들어 사용자의 조회 시간을 추가합니다.
  2. arrayUnion 사용: 새로운 조회 시간을 lastViewed 배열에 추가합니다.

Firestore 구조:

/views/{postId}/users/{userId or anonymousId}
{
  lastViewed: [Timestamp1, Timestamp2, Timestamp3, ...] // 조회 시간 배열
}

코드 예시

아래 코드는 사용자가 글을 조회할 때마다 조회 시간을 lastViewed 배열에 추가하는 방식으로 구현되었습니다.

import { db } from './firebase'; // Firestore 초기화
import { doc, getDoc, setDoc, arrayUnion, serverTimestamp } from 'firebase/firestore';

// 조회 기록 업데이트 함수
async function updateViewCount(postId, userId = null) {
  const now = new Date();
  let viewId;

  // 비회원일 경우 로컬 스토리지 또는 쿠키를 사용하여 고유 ID 생성
  if (!userId) {
    viewId = getAnonymousId(); // 비회원에 대한 고유 ID 가져오기
  } else {
    viewId = userId; // 회원일 경우 사용자 ID
  }

  const viewDocRef = doc(db, 'views', postId, 'users', viewId);

  // Firestore에서 해당 사용자의 조회 기록을 가져옵니다.
  const viewDoc = await getDoc(viewDocRef);

  if (viewDoc.exists()) {
    // 오늘 조회 기록이 있는지 확인
    const lastViewed = viewDoc.data().lastViewed;
    const today = new Date().toDateString();
    const viewedToday = lastViewed.some(view => view.toDate().toDateString() === today);

    if (viewedToday) {
      console.log("이미 오늘 조회하였습니다.");
      return;
    }
  }

  // Firestore의 lastViewed 배열에 조회 시간을 추가
  await setDoc(viewDocRef, {
    lastViewed: arrayUnion(serverTimestamp()) // 배열에 서버 시간을 추가
  }, { merge: true });

  console.log("조회수가 증가되었습니다.");
}

코드 설명

  1. arrayUnion() 사용:
    1. Firestore의 arrayUnion() 함수는 배열에 중복되지 않는 항목을 추가합니다.
    2. 여기서 serverTimestamp()는 Firestore 서버 시간을 자동으로 저장해줍니다.
    3. 배열에 새로운 조회 시간이 추가되며, 기존 기록은 유지됩니다.
  2. 조회 기록 확인:
    1. getDoc()을 사용하여 해당 사용자의 조회 기록을 가져오고, lastViewed 배열에 오늘의 조회 기록이 있는지 확인합니다.
    2. 오늘 이미 조회한 기록이 있으면 조회수를 증가시키지 않고, 새로운 조회 시간이 배열에 추가되지 않습니다.
  3. 비회원 처리:
    1. 비회원은 getAnonymousId()를 통해 익명 ID를 사용하여 조회 기록을 관리합니다.

Firestore에 저장된 예시 데이터:

/views/abc123/users/user_1
{
  lastViewed: [
    September 5, 2024, 10:15:00 AM UTC,
    September 6, 2024, 09:45:30 AM UTC
  ]
}

/views/abc123/users/anon_9sdfsdf
{
  lastViewed: [
    September 6, 2024, 08:15:42 AM UTC
  ]
}
  • lastViewed 배열에는 사용자가 해당 글을 조회한 시간들이 Timestamp 형식으로 계속 추가됩니다.
  • arrayUnion()을 사용하면 Firestore에서 중복된 값 없이 자동으로 배열에 새로운 시간을 추가해줍니다.

Vue 컴포넌트에서 조회수 관리

이 기능을 Vue 컴포넌트에 적용하는 방식은 다음과 같습니다. 컴포넌트가 생성될 때 updateViewCount() 함수를 호출해 Firestore에 조회 시간을 추가합니다.

<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
    <p>조회수: {{ post.viewCount }}</p>
  </div>
</template>

<script>
import { db } from '../firebase';
import { doc, getDoc } from 'firebase/firestore';
import { updateViewCount } from '../utils/viewHandler'; // 조회수 업데이트 함수

export default {
  data() {
    return {
      post: {},
    };
  },
  async created() {
    const postId = this.$route.params.id;
    await this.fetchPost(postId);

    const userId = this.$store.state.user ? this.$store.state.user.id : null; // 로그인 여부 확인
    await updateViewCount(postId, userId); // 조회수 업데이트 및 기록
  },
  methods: {
    async fetchPost(postId) {
      const docRef = doc(db, 'posts', postId);
      const docSnap = await getDoc(docRef);
      if (docSnap.exists()) {
        this.post = docSnap.data();
      } else {
        console.log("게시글이 존재하지 않습니다.");
      }
    }
  }
};
</script>

요약

Firestore에서 lastViewed 배열을 사용하여 조회 기록을 계속 추가할 수 있습니다. arrayUnion() 함수를 사용해 중복되지 않는 새로운 조회 시간을 배열에 추가하고, 중복 조회를 방지합니다. 이 구조를 통해 사용자별로 조회 기록을 쉽게 관리할 수 있으며, 각 사용자의 조회 기록을 일자별로 추적할 수 있습니다.

'Vue로 PWA 개발' 카테고리의 다른 글

27. mylog 기본 워크플로우 완성  (0) 2024.10.24
26. mylog 익명 ID  (0) 2024.10.24
24. mylog 조회수 컬렉션  (0) 2024.10.23
23. mylog 조회수  (0) 2024.10.23
22. mylog 쓰기  (0) 2024.10.23