[MongoDB] Mongoose Transaction 사용하기

2025. 5. 16. 22:45·Development/DB

게시글, 리뷰에 좋아요 기능을 구현하다가 mongoose transaction이라는 것을 알게되어 사용했다.

기억하고 다음에도 쓰기 위해 기록해본다.

 

참고 :
https://velog.io/@moongq/mongoose-transaction

 

 

1. Mongoose Transaction

transaction은 복수개의 작업들이 모두 성공했을 경우 성공하게 되고, 하나라도 실패했을 경우 실패 처리한다.

MongoDB에서는 mongoose session으로 트랜잭션 처리가 가능하다. 이때 몽고의 버전은 5.2.0 이상이어야한다.

 

2. Express.js 코드

 

좋아요 기능을 구현하기 위해 mongoose transaction을 사용해보자.

 

LikeSchema.index({ userId: 1, postId: 1 }, { unique: true })

 

일단 중복을 방지하기 위해 좋아요 스키마에서 unique를 설정해준다.

 

const session = await mongoose.startSession()
session.startTransaction()

 

session을 startSession()으로 생성하고 startTransaction()으로 트랜잭션을 활성화한다.

 

try {
  await this.Likes.create([{ userId, boardId }]).session(session)
  await this.Board.findByIdAndUpdate(
    boardId,
    { $inc: { likesCnt: 1 } },
  ).session(session)

  await session.commitTransaction()
}

 

배열 형태로 userId, boardId를 저장해주고 .session(session)으로 세션을 설정해준다.

.session(session)가 붙지 않은 (세션 객체가 명시되지 않은) 쿼리는 트랜잭션과 무관하게 작동하기 때문에 반드시 설정해준다.

 

boardId를 가진 게시글에 좋아요 수를 1 증가 또는 감소 시켜준다. $inc가 그 역할을 한다.

.commitTransaction()으로 모든 작업을 커밋한다.

 

이제 이 코드를 리팩터링 해볼 것이다.

 

try {
  // await this.Likes.create([{ userId, boardId }]).session(session)
  // await this.Board.findByIdAndUpdate(boardId, {
  //   $inc: { likesCnt: 1 },
  // }).session(session)

  // await session.commitTransaction()

  await session.withTransaction(async () => {
    await this.Likes.create({ userId, boardId }).session(session)

    await this.Board.updateOne(
      { _id: boardId },
      { $inc: { likesCnt: 1 } }
    ).session(session)
  })
  session.endSession()

  return { success: true }
}

 

세션을 좀 더 편하게 쓰기 위해 .withTransaction()을 사용했다. withTransaction()은 startTransaction()과 commitTransaction()을 한 줄로 줄여준다. 따라서 위의 startTransaction() 부분도 주석처리 해준다.

추가로 findByIdandUpdate 대신 updateOne을 사용했다.

 

catch (err) {
  await session.abortTransaction()
  session.endSession()
  if (err.code == 11000) {
    throw { status: 400, message: "이미 처리된 좋아요" }
  }
  throw err
}

 

예외 처리도 마저 해준다. err.code == 11000 는 몽고에서 중복 키 에러가 발생했을 경우 나타나는 에러다.

 

전체 코드

 

try {
    // await this.Likes.create([{ userId, boardId }]).session(session)
    // await this.Board.findByIdAndUpdate(boardId, {
    //   $inc: { likesCnt: 1 },
    // }).session(session)

    // await session.commitTransaction()

    await session.withTransaction(async () => {
      await this.Likes.create({ userId, boardId }).session(session)

      await this.Board.updateOne(
        { _id: boardId },
        { $inc: { likesCnt: 1 } }
      ).session(session)
    })
    session.endSession()

    return { success: true }
  } catch (err) {
    await session.abortTransaction()
    session.endSession()
    if (err.code == 11000) {
      throw { status: 400, message: "이미 처리된 좋아요" }
    }
    throw err
  }
}

 

업그레이드 된 좋아요 기능 포스트!!

https://knhye.tistory.com/31

 

감사합니다 ヾ(⌐■_■)ノ

'Development > DB' 카테고리의 다른 글

[JPA] 카테시안 곱 발견 후 해결 과정 (1)  (0) 2025.10.28
[Express+MongoDB] 검색 기능 구현 (MongoDB Atlas Search Index)  (0) 2025.04.08
'Development/DB' 카테고리의 다른 글
  • [JPA] 카테시안 곱 발견 후 해결 과정 (1)
  • [Express+MongoDB] 검색 기능 구현 (MongoDB Atlas Search Index)
knhye
knhye
  • 전체
    오늘
    어제
  • knhye
    3n1hye_
    knhye
  • 링크

    • GitHub
    • 분류 전체보기 (61)
      • Development (28)
        • Back-end (21)
        • DB (3)
        • CS (4)
      • Algorithm (6)
      • DevOps (10)
        • git (1)
        • Cloud Platform (5)
        • CICD (1)
        • Cloud Native (2)
      • Internet (2)
      • 매일메일 (6)
      • 회고 (5)
        • Capstone (2)
        • Hackathon (1)
        • 2025 (2)
      • 자격증 (1)
      • 블로그 리딩 (3)
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
knhye
[MongoDB] Mongoose Transaction 사용하기
상단으로

티스토리툴바