개인 프로젝트에서 firebase
를 사용하기에, 평소에 신경쓰지 않아도 괜찮던 DB구조에 대해 생각해봐야하는 상황이 발생하였습니다.
컬렉션 | 데이터 | 서브컬렉션 | 데이터 |
---|---|---|---|
posts | post | comments | comment |
- | - | reactions | reaction |
users | user | - | - |
게시물 같은 경우 위와 같은 형태로 posts
라는 컬력션 아래 각각의 게시물이 저장되며, 그 게시물의 서브 컬렉션에 comments
, reactions
두개의 서브 컬렉션이 위치하고 있습니다.
그리고 users
라는 컬렉션에 유저들의 정보를 저장하고 있습니다.
위와 같이 컬렉션 구조가 설계되어 있으나, 클라이언트 부분에서 게시물을 표시하기 위해 필요한 데이터는
이렇게 4가지의 데이터가 필요합니다.
하지만 Firebase
는 NoSQL
기반에 서비스이기에 컬렉션을 하나의 필드로 join
할 수 없기에 문제가 발생하였습니다.
문제를 해결하기 위해, post
하나에 user
, comment
, reaction
를 모두 취합하여 관리하게 되면 문제가 해결되나 이 방법의 문제점은 아래와 같습니다.
파이어베이스에서 데이터의 병합이 불가능하다면, 필요한 데이터들을 호출한 후, 클라이언트단에서 병합해 join
과 같은 효과를 구현하기로 했다.
export const getPost = async (id: string) => {
const postDoc = await getDoc(doc(db, POST_COLLECTION, id));
const { createdAt, ...postData } = postDoc.data() as PostFirebase;
const userPromise = getUser(postData.uid);
const reactionsPromise = getReactionList(postDoc.id);
const commentsPromise = getCommentList(postDoc.id);
const [user, reactions, comments] = await Promise.all([
userPromise,
reactionsPromise,
commentsPromise
]);
return {
id: postDoc.id,
user,
reactions,
comments,
createdAt: createdAt.toDate(),
...postData
} as PostClient;
};
위와 같이 getUser
, getReactionList
, getCommentList
를 통해 필요한 데이터를 호출, Promise.all
을 통해서 병렬로 처리해주었습니다.
위와 같은 방법은 원하는 형태로 데이터를 받아올 수 있으나, 서버에서 데이터를 정제해주는게 아니기에, 너무 많은 호출이 발생합니다.
많은 호출은 결국에 서버비용을 증가시키기에 아직 문제점이 남아있습니다.
Firebase
가 아닌 관계형 데이터베이스를 지원하는 back4app
, AWS Amplify
와 같은 서비스가 이런 프로젝트에 더 어울리는 것 같아 다음 프로젝트에서는 도입해보려 합니다.