
SNS 팀프로젝트에서 채팅 기능 구현을 위해 Firebase의 Firestore를 이용해보았다. 실시간 채팅을 구현하면서 느꼈던 점들을 간단히 정리해보고자 한다.
onSnapshot 메서드를 통해 실시간 업데이트가 이루어지기 때문에 실시간 채팅 기능 구현에 적합하다.위와 같은 이유로 Firebase를 사용했다. 구현하고자 한 바 역시 아주 기본적인 기능들만 구현하려 했기 때문에 굳이 다른 서비스를 찾지 않았다. 결과적으로 구현을 완성하긴 했지만, 역시 스택을 선택함에 있어서는 조금 더 신중한다는 것을 배웠다. (이와 관련해서는 뒤에 자세히 적을 것이다.)
이번 프로젝트는 부트캠프 내에서 진행한 팀 프로젝트였고, API를 교육기관에서 제공해주었기 때문에 데이터 구조를 설계하는 데 있어서 분명히 한계가 있었다. 그래서 일반적인 채팅 데이터 구조와는 차이가 있을 것이라 생각한다.
기본적으로 채팅방에 대한 정보가 담긴 chatList, 각 채팅방 별로 메세지가 저장되는 messages, 채팅방아이디와 참여자 정보가 담긴 rooms로 세 개의 컬렉션을 만들었다. 각 컬렉션의 데이터 구조는 다음과 같다.

chatList컬렉션과 rooms 컬렉션은 그 내용이 완전히 겹친다. 그런데 이렇게 나눈 이유는 프로필 페이지에서 메세지 보내기 버튼을 클릭했을 때 이미 채팅을 한 이력이 있는지, 아니면 새로 생성해야 하는지를 확인하기 위해서였다.
user 프로필 데이터에 참여하고 있는 채팅방 id를 저장해두면 이 과정이 쉬웠겠으나, 제공된 api를 사용하고 있었기 때문에 프로필 데이터에 채팅방 id를 넣을 수가 없었다. 그리고 chatList 컬렉션에서 이를 판별하려고 하니, 전체 리스트를 불러와서 참여자를 필터를 해야했기 때문에 그 과정이 복잡해졌다. 이러한 이유로 필터를 제일 적게 하기 위한 방법으로 rooms를 따로 만들었다.
사실 확장성이나 데이터 수정, 삭제 등을 고려해보았을 때, messages은 하위컬렉션을 생성하여 각 메세지를 개별적으로 저장하는 것이 더 알맞은 방법이라고 생각한다. 왜냐하면 Firestore의 각 문서는 최대 1MB이므로 저장할 수 있는 메세지의 한계가 있다. 하지만, 이 프로젝트는 규모가 작기 때문에 굳이 나누지 않았다. 만약에 다시 구현을 한다면 개별 메세지로 모두 나눌 것이다.
Firestore는 안타깝게도 join 연산을 제공하지 않는다. 그래서 매번 사용자 계정과 프로필 이미지 등의 데이터를 넣어줘야한다는 것이 다소 불편했다. Firestore가 NoSQL 방식이다 보니 어쩔 수 없는 부분이었다.
Supabase는 PostgreSQL을 기반으로 하며 sql의 기능들을 제공한다고 하는데, 다음에 채팅을 구현해야한다면 Supabase를 이용해보면 좋을 것 같다.