devcisive / solumon-frontend

0 stars 3 forks source link

firestore에 저장된 기존 필드를 유지하면서 새로운 값을 추가하는 방법 - arrayUnion #71

Closed chaeeunj closed 8 months ago

chaeeunj commented 8 months ago

사용자가 투표에 참여한 게시글의 postId를 사용자의 정보가 저장된 컬렉션 문서에 객체 형태로 저장하고 싶은데 어떤 방식으로 코드를 작성해야 할지 고민이 되어 여러 시도를 해보았습니다.

저장하고 싶은 형태 join_posts = [ {postId: 'asdfs'}, {postId: 'qwert'}, {postId: 'zxcvb'}, .... ]

image 노란색으로 강조한 부분이 해당 문서의 id를 의미하고 저희는 id값을 postId 라는 변수로 지정했습니다.


일단 현재 사용자를 user 변수로 설정한 후 회원들의 정보가 저장된 users 컬렉션의 문서 중 uid 필드가 현재 사용자의 uid와 같은 문서의 데이터를 가져옵니다. (firestore의 users 컬렉션에는 각 회원마다 하나의 문서에 저장되어 있고 이 문서에는 회원의 닉네임, uid, 관심주제가 저장되어 있습니다.)

const updateVoteJoin = async () => {
    try {
      const user = auth.currentUser;

      //파이어스토어에서 'users'컬렉션을 쿼리설정한 다음 uid 필드가 result.user.uid와(현재 유저의 uid와) 같은 문서 찾기
      const userQuery = query(
        collection(db, 'users'),
        where('uid', '==', user.uid),
      );

      const querySnapshot = await getDocs(userQuery);
      const userDoc = querySnapshot.docs[0];

    } catch (error) {
      console.error(error);
    }
  };

지금부터 작성하는 시도해본 코드는 전부 const userDoc = querySnapshot.docs[0]; 의 하단에 작성됩니다.


  1. 첫 번째 시도 updateDoc() 을 사용하여 해당 문서에 postId 라는 키값을 가진 join_posts 를 업데이트하는 방법
    if (userDoc) {
        // users collection중 현재 로그인한 유저의 userDoc.id값과 일치한 문서를 찾아 업데이트함
        await updateDoc(doc(db, 'users', userDoc.id), {
          join_posts: { postId },
        });
    }

    이 방법은 투표에 참여했을 때 해당 게시글의 postId 값을 firestore 문서에 잘 저장했지만, 투표에 참여한 게시글의 postId가 전부 저장되는 것이 아니라 가장 최근에 투표한 글의 postId 값 하나만 계속 업데이트되며 저장된다는 문제점이 있었습니다.


  1. 두 번째 시도 새로운 배열을 생성해서 이미 저장되어 있던 값을 복사한 다음 새로 투표에 참여한 글의 postId를 저장하고, 이 배열을 join_posts 필드 값으로 업데이트 하는 방식

    
    if (userDoc) {
        // users 문서에 join_posts 필드가 있다면 그 값을 가져오고 없다면 빈 배열 생성
        const existingJoinPosts = userDoc.data().join_posts || [];
    
        // postId가 join_posts 배열에 있는지 확인
        if (!existingJoinPosts.some((joinPost) => joinPost.postId === postId)) {
          const updatedJoinPosts = [...existingJoinPosts, { postId }];
    
          await updateDoc(doc(db, 'users', userDoc.id), {
            join_posts: updatedJoinPosts,
          });
        }
      }
이 방법은 처음에 투표에 참여한 글의 postId 값 하나만 저장이 되고, 다른 게시글의 투표에 참여해도 해당 postId 는 업데이트되지 않는 문제가 있었습니다.

<br />

3. 마지막 시도
**arrayUnion() 을 사용하여 기존에 투표에 참여한 글의 postId 를 유지하며 새로 투표에 참여한 글의 postId를 join_posts 필드에 추가하는 방식**
```javascript
 if (userDoc) {
        await updateDoc(doc(db, 'users', userDoc.id), {
          join_posts: arrayUnion({ postId }),
        });
      }

다른 방식을 찾아보던 중 firestore에서 배열 필드를 업데이트(배열에 없는 요소만 추가) 해주는 arrayUnion() 함수를 제공한다는 것을 알게 되었습니다. 이렇게 코드를 수정하고 나니 image join_posts 필드가 제대로 업데이트 되며 원하는 형태로 postId 값들이 저장된 것을 확인할 수 있었습니다.


참고

결과적으로 파일에 import 할 것들

import { db, auth } from '../firebase-config'; // 파이어베이스 사용에 필요한 것들을 초기화해둔 파일
import {
  arrayUnion,
  updateDoc,
  doc,
  getDoc,
  getDocs,
  collection,
  query,
  where,
} from 'firebase/firestore'; // 파이어베이스와 파이어스토에서 제공하는 함수들