Vue로 PWA 개발

23. mylog 조회수

그랜파 개발자 2024. 10. 23. 15:02

마이로그의 조회수는 사용자가 로그인을 하지 않아도 카운트되며, 한 사용자에 대해 하루에 여러번 조회를 해도 하루에 한번만 카운트합니다.

ChatGPT에게 물었습니다.

forestore를 사용하고 쓴글에 대해 회원이든 아니든 하루 몇번을 방문하든 조회수는 하나로 한 조회수를 알고 싶어.

 

ChatGPT

Firestore를 사용하여 작성된 글에 대해, 회원이든 비회원이든 하루에 여러 번 방문해도 조회수를 한 번만 증가시키는 방법을 구현할 수 있습니다. 이 작업은 Firestore에 사용자별로 조회 기록을 저장하고, 하루에 한 번만 조회수를 증가시키는 방식으로 해결할 수 있습니다.

요구사항 분석

  1. 회원: 회원일 경우 회원 ID를 기준으로 조회 여부를 판단하여 조회수를 하루에 한 번만 증가시킵니다.
  2. 비회원: 비회원일 경우 쿠키 또는 로컬 스토리지를 사용해 고유한 ID를 부여하고, 이를 기준으로 조회수를 관리합니다.
  3. 조회수: 글의 조회수는 Firestore에 저장되고, 매일 첫 번째 방문에만 조회수가 증가됩니다.

Firestore 구조 설계

  • posts 컬렉션: 글의 정보(글 제목, 내용, 조회수 등)를 저장합니다.
  • views 컬렉션: 각 글에 대한 사용자별 조회 기록을 저장합니다.

Firestore 구조 예시:

/posts/{postId} /views/{postId}/users/{userId or anonymousId}

1. Firestore에 조회수 저장 및 조회 기록 관리

아래 코드는 Firestore에서 조회수를 관리하는 함수입니다. 이 함수는 사용자가 해당 글을 이미 오늘 조회했는지 확인하고, 조회하지 않았다면 조회수를 1 증가시킵니다.

import { db } from './firebase'; // Firestore 초기화
import { doc, getDoc, setDoc, increment, 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);
  const postDocRef = doc(db, 'posts', postId);

  const viewDoc = await getDoc(viewDocRef);

  // 사용자가 오늘 조회한 기록이 있는지 확인
  if (viewDoc.exists()) {
    const lastViewed = viewDoc.data().lastViewed.toDate();
    if (isSameDay(lastViewed, now)) {
      console.log("이미 오늘 조회하였습니다.");
      return;
    }
  }

  // Firestore에 조회 기록 추가 (또는 업데이트)
  await setDoc(viewDocRef, {
    lastViewed: serverTimestamp() // 서버 시간 저장
  });

  // 게시글의 조회수 1 증가
  await setDoc(postDocRef, {
    viewCount: increment(1) // 조회수 1 증가
  }, { merge: true });

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

// 날짜 비교 함수
function isSameDay(date1, date2) {
  return date1.getFullYear() === date2.getFullYear() &&
         date1.getMonth() === date2.getMonth() &&
         date1.getDate() === date2.getDate();
}

// 비회원 고유 ID 생성 (쿠키나 로컬 스토리지에서 ID 관리)
function getAnonymousId() {
  let anonymousId = localStorage.getItem('anonymousId');
  if (!anonymousId) {
    anonymousId = 'anon_' + Math.random().toString(36).substr(2, 9); // 랜덤 ID 생성
    localStorage.setItem('anonymousId', anonymousId); // 로컬 스토리지에 저장
  }
  return anonymousId;
}

2. Vue 컴포넌트에서 조회수 업데이트 호출

작성된 글을 조회할 때마다 위 updateViewCount 함수를 호출하여 조회수를 업데이트합니다. 이때, 로그인한 사용자는 userId를, 비회원은 익명 ID를 사용해 조회수를 관리합니다.

<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>

3. 주요 로직 설명

  • 조회수 업데이트 (updateViewCount): 사용자가 해당 글을 오늘 이미 조회했는지 Firestore에서 확인합니다. 오늘 조회한 기록이 있으면 조회수를 증가시키지 않고, 기록이 없으면 Firestore의 views 컬렉션에 조회 기록을 추가하고 posts 컬렉션의 viewCount를 1 증가시킵니다.
  • 비회원 처리: 비회원의 경우 로컬 스토리지를 사용하여 고유한 익명 ID를 생성하고, 이를 기준으로 조회수를 관리합니다. 익명 ID는 getAnonymousId() 함수를 통해 생성되고 저장됩니다.
  • 날짜 비교 (isSameDay): 조회 기록이 오늘 것인지 확인하는 함수입니다. 사용자가 마지막으로 조회한 날짜와 현재 날짜를 비교하여, 같은 날이면 조회수를 증가시키지 않습니다.

4. 비회원 ID 관리

비회원의 경우 쿠키나 로컬 스토리지를 사용하여 고유한 익명 ID를 생성하고 저장합니다. 이 익명 ID를 통해 비회원도 하루에 한 번만 조회수가 증가하도록 관리할 수 있습니다.

5. Firestore에서 조회수 확인

Firestore의 posts 컬렉션에는 각 게시글의 조회수가 저장됩니다. 예를 들어, Firestore에서 posts 컬렉션을 확인하면 다음과 같이 조회수를 확인할 수 있습니다:

/posts/{postId} /views/{postId}/users/{userId or anonymousId}

 

게시글마다 viewCount 필드가 있고, 이 필드는 조회수가 증가될 때마다 1씩 증가합니다.

결론

이 방법을 통해 회원이든 비회원이든 하루에 여러 번 방문하더라도 조회수를 한 번만 증가시키는 기능을 구현할 수 있습니다. Firestore의 views 컬렉션에서 사용자별 조회 기록을 관리하고, 날짜를 비교하여 조회수를 하루에 한 번만 증가시키는 로직을 적용했습니다.

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

25. mylog 날짜별 조회수  (0) 2024.10.24
24. mylog 조회수 컬렉션  (0) 2024.10.23
22. mylog 쓰기  (0) 2024.10.23
21. mylog 홈페이지  (0) 2024.10.22
20. mylog 접속  (1) 2024.10.22