Vue로 PWA 개발

61. myLog 보기 정렬

그랜파 개발자 2024. 11. 3. 16:35

Vue로 PWA 개발 - 그랜파 개발자

 

‘내로그’ 메뉴를 눌러 나의 마이로그 목록을 볼 때 기본은 작성일 역순으로 보입니다. 그런데 마이로그 중 조회순으로 보고 싶을 때가 있습니다. 그래서 ‘내로그’ 페이지에 정렬 방법에 대한 ‘최신순’, ‘조회순’ 두 개의 버튼을 추가합니다. ‘최신순’은 작성일 역순으로 정렬을 하고, ‘조회순’은 조회수가 많은 순서로 정렬하여 보여줍니다.

1. 쿼리

마이로그 보기 정렬을 위한 쿼리입니다.

  • 최신순 쿼리입니다.
    query(collection(db, "mylogs"), where("userId", "==", userId), orderBy("createdAt", "desc"));
  • 조회순 쿼리입니다.
    query(collection(db, "mylogs"), where("userId", "==", userId), orderBy("views", "desc"));

위의 쿼리를 보면 where와 orderBy를 사용합니다. 이로 인해 복합 색인이 필요합니다.
firestore는 단일 필드 색인, 복합 색인이 있습니다.

  • 단일 필드 색인(single field index) - 필드 하나로 구성된 색인
  • 복합 색인(composite index) - 필드 여러개로 구성된 색인

Firestore에서는 자동으로 생성되는 단일 필드 색인과는 달리 복합 색인을 자동으로 만들지 않습니다. 가능한 필드 조합 수가 많기 때문입니다. 대신 Firestore를 통해 앱을 빌드할 때 필요한 복합 색인을 식별하고 만들 수 있습니다.

필수 색인부터 만들지 않고 위의 쿼리를 시도하면 Firestore에서 링크가 포함된 오류 메시지를 반환합니다. 이 링크로 이동하면 누락된 색인을 만들 수 있습니다. 색인에서 지원하지 않는 쿼리를 시도할 때마다 이러한 오류가 발생합니다. 또한 Console이나 Firebase CLI를 사용하여 직접 복합 색인을 정의하고 관리할 수 있습니다.

 

Firebase Console에서 수동으로 새 색인을 만들려면 다음과 같이 합니다.

  1. Firebase Console의 Cloud Firestore 섹션으로 이동합니다.
  2. 색인 탭으로 이동하고 색인 추가를 클릭합니다.
  3. 컬렉션 이름을 입력하고 색인의 정렬 기준으로 사용할 필드를 설정합니다.
  4. 만들기를 클릭합니다.

https://cloud.google.com/firestore/docs/concepts/index-overview?hl=ko 참조했습니다.

 

2. 마이로그 정렬

 

3. src/views/MyMyLogsView.vue

<!-- src/views/MyMyLogsView.vue -->
<template>  
  <v-container> 
    <v-card>
      <v-card-title>{{ getMylogName }}</v-card-title>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="viewByDate"> 최신순 </v-btn> 
        <v-btn @click="viewByViews"> 조회순 </v-btn> 
      </v-card-actions>
      <v-list v-if="userMylogs.length > 0">
        <v-list-item v-for="mylog in userMylogs" :key="mylog.id" @click="goToMylogDetail(mylog.id)">
          <v-list-item-content>
            <v-list-item-title>{{ mylog.title }}</v-list-item-title>
            <v-list-item-subtitle>{{ mylog.createdAt.toDate().toLocaleDateString() }} ({{ mylog.views }})</v-list-item-subtitle>
            <v-list-item-subtitle>{{ mylog.content }}</v-list-item-subtitle>

          </v-list-item-content>
        </v-list-item>
      </v-list>
      <p v-else>You haven't written any posts yet.</p>
    </v-card>
  </v-container>
</template>

<script>
import { mapActions, mapGetters } from "vuex";

export default {
  data() {
    return { 
    };
  }, 
  computed: {
    ...mapGetters('mylogs',['userMylogs']),
    getMylogName() {
      return this.$store.state.auth.user.mylogname;
    }
  },
  methods: {
    ...mapActions('mylogs', ['fetchUserMylogs', 'fetchUserMylogsOrderByViews']),
    goToMylogDetail(mylogId) {
      this.$router.push({ name: 'MyLogView', params: { id: mylogId } });
    },
    viewByDate() { 
      const userId = this.$store.state.auth.user.id;
      this.fetchUserMylogs(userId); // 본인 작성 글 가져오기    
    },
    viewByViews() { 
      const userId = this.$store.state.auth.user.id;
      this.fetchUserMylogsOrderByViews(userId); // 본인 작성 글 가져오기    
    }
  },
  mounted() {
    const userId = this.$store.state.auth.user.id;
    this.fetchUserMylogs(userId); // 본인 작성 글 가져오기    
  }
};
</script>

 

4. src/store/modules/mylogs.js

// src/store/modules/mylogs.js
import router from '@/router';  // Vue Router import
import { v4 as uuidv4 } from 'uuid';
import { db, doc, collection, getDoc, getDocs, addDoc, setDoc, updateDoc } from "@/firebase";
import { deleteDoc, query, orderBy, arrayUnion, increment, where  } from "@/firebase";

const state = {
  . . . 
  userMylogs: [],     // 본인이 작성한 글 저장
  . . .
};

const mutations = {
  . . .
  setUserMylogs(state, mylogs) {
    state.userMylogs = mylogs;
  },
  . . .
};

const actions = {
  . . .
  // 현재 사용자가 작성한 게시물 불러오기 - 조회수 역순 정렬
  async fetchUserMylogsOrderByViews({ commit }, userId) {
    if (userId) { 
      try {
        const q = query(collection(db, "mylogs"), where("userId", "==", userId), orderBy("views", "desc"));
        const querySnapshot = await getDocs(q);
        const mylogs = [];
        querySnapshot.forEach((doc) => {
          mylogs.push({ id: doc.id, ...doc.data() });
        }); 
        commit('setUserMylogs', mylogs); // 상태에 저장
      } catch (error) {
        console.error("본인 글 가져오기 실패:", error);
        commit('setError', error);  
      }
    }
  },

  // 현재 사용자가 작성한 게시물 불러오기 - 작성일 역순 정렬
  async fetchUserMylogs({ commit }, userId) {
    if (userId) { 
      try {
        const q = query(collection(db, "mylogs"), where("userId", "==", userId), orderBy("createdAt", "desc"));
        const querySnapshot = await getDocs(q);
        const mylogs = [];
        querySnapshot.forEach((doc) => {
          mylogs.push({ id: doc.id, ...doc.data() });
        }); 
        commit('setUserMylogs', mylogs); // 상태에 저장
      } catch (error) {
        console.error("본인 글 가져오기 실패:", error);
        commit('setError', error);  
      }
    }
  },
  . . .
};

const getters = {
  . . .
  userMylogs: state => state.userMylogs,
  . . .
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
};



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

62. mylog 끝  (0) 2024.11.03
60. myLog 날짜별 조회수 구현  (0) 2024.11.03
59. myLog 날짜별 조회수  (1) 2024.11.03
58. mylog 통계  (0) 2024.11.03
57. mylog 구독자 알림 전송  (0) 2024.11.02