HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📯
부스트캠프 7기 BE 멤버쉽 설계
/
mongodb 게시글 카운트

mongodb 게시글 카운트

요약
확인
확인
레이블
12주차
https://github.com/boostcampwm-2022/web34-moheyum/tree/dev/server/src
그룹 프로젝트에서 트위터와 유사한 SNS를 개발하고 있습니다.
백엔드는 Nest.js + Mongoose(MongoDB) 로 진행중입니다.
notion image
유저 프로필 페이지에서 게시글, 팔로워, 팔로잉 수를 반환해야 하는데, 이를 어떻게 구현해야 할지 고민입니다.
 

현행

 
유저 스키마에 카운트를 두고 있습니다.
위와 같이 게시글의 수가 증감하는 상황에 유저 카운트를 1씩 증가/감소 시키는 방향으로 하고 있습니다.

이렇게 구현한 이유

  • 빠릅니다.

현행의 문제

의도치 않게 카운트가 어긋나는 경우가 생깁니다. 예를 들어,
  • 게시글 추가/삭제가 되지 않았는데도 카운트가 증감되거나
  • 카운트를 1 증감시키는 액션이 의도치 않게 취소되거나
  • 테스트를 위해 DB 상에 직접 추가하는 경우

고민중인 다른 대안

  1. 카운트 수를 요청할 때마다 계산
      • MongoDB에서는 count, countDocuments 를 제공합니다.
      • 현재 50만 개 정도의 포스트가 있고, 작성자 기준으로 인덱싱했음에도 불구하고 카운트를 세는 것이 2~300ms 정도로 오래 걸립니다.
      • MongoDB의 B+ tree indexing에 count 정보를 포함하지 않기 때문에 인덱싱 탐색을 하더라도 leaf 하나 하나 다 확인하기 때문인 것으로 파악이 됩니다. (MySQL은 ISAM에서만 인덱싱을 통한 O(1) 카운트를 지원하고, InnoDB는 마찬가지로 O(n) 인것으로 파악됨)
      • 게시글 수가 100개 미만인 유저의 게시글 카운트는 1ms 안팎이지만 게시글 50만개를 작성한 유저 기준으로 2~300ms가 소요됩니다.
      • 프로필을 조회할 때마다 DB를 300ms 를 쓰는 것은 너무 부담됩니다.
  • 현재 50만 개 정도의 포스트가 있고, 작성자 기준으로 인덱싱했음에도 불구하고 카운트를 세는 것이 2~300ms 정도로 오래 걸립니다.
  • MongoDB의 B+ tree indexing에 count 정보를 포함하지 않기 때문에 인덱싱 탐색을 하더라도 leaf 하나 하나 다 확인하기 때문인 것으로 파악이 됩니다. (MySQL은 ISAM에서만 인덱싱을 통한 O(1) 카운트를 지원하고, InnoDB는 마찬가지로 O(n) 인것으로 파악됨)
  • 게시글 수가 100개 미만인 유저의 게시글 카운트는 1ms 안팎이지만 게시글 50만개를 작성한 유저 기준으로 2~300ms가 소요됩니다.
  • 프로필을 조회할 때마다 DB를 300ms 를 쓰는 것은 너무 부담됩니다.
  1. 게시글 추가/삭제를 할 때마다 카운트 수를 계산하여 유저 rows에 보관
      • 현행과 마찬가지로 카운트 업데이트 도중 취소되는 것에 어떻게 대처해야 할지 모르겠습니다. → 트랜잭션
      • 게시글을 쓰고 지우거나, 팔로잉을 추가하고 취소할 때마다 인덱스 크기가 50만 기준으로 2~300ms가 소요될 것입니다.
       
어떻게 해야 DB에 부담이 덜 가면서 빠르게 게시글/팔로워/팔로잉 카운트를 반환할 수 있을까요?
 
CQRS?
 
redis + transaction
 
@Schema({ versionKey: false, timestamps: true }) export class User { ... @Prop({ default: 0, }) postcount: number; @Prop({ default: 0, }) follower: number; @Prop({ default: 0, }) following: number; ... }
async createPost(createBoardDto: CreatePostDto, user: User): Promise<Post> { const post = await this.postRepository.create(createBoardDto, user); this.userRepository.updatePostCount({ userid: user.userid }, 1); return post; }
async updatePostCount(userFilterQuery: FilterQuery<User>, postCount: number) { const result = this.userModel.findOneAndUpdate( userFilterQuery, { $inc: { postcount: postCount }, }, { new: true }, ); if (!result) throw new NotFoundException(); return result; }
async createPost(createBoardDto: CreatePostDto, user: User): Promise<Post> { const post = await this.postRepository.create(createBoardDto, user); this.userRepository.updatePostCount({ userid: user.userid }); //여기서 업데이트를 한다면? return post; }