BackEnd/Database

[MongoDB] Mongoose Populate 이해 - find의 결과를 populate가 필터링 하지 않음

꼽파 2024. 8. 31. 12:58
프로젝트 리팩토링을 아직도 하고 있는데, 검색 API를 만들다가 쿼리를 제대로 사용하지 못하여 시간을 엄청 허비하는 일이 있었다.
결론부터 말하면 1번 코드로 작동해서 안 되다가 2번 코드로 수정하니 잘 해결되었다.
이게 왜 안 되는지 파악하는데 꽤 많은 시간이 걸렸다.
 

 

상황 : feed 모델 안에 travelPlan 모델을 populate한 상태임.

1번

결과 : 모든 글이 다 조회됨.
    // 제목
    // travelPlan의 title
    if (title) {
      const feeds = await this.feedModel
        .find()
        .populate({
          path: 'travelPlan',
          match: { title: title }
        })
        .exec();

      searchResult.push(...feeds);
    }
select는 빼고 해봄.
전체 글 32개가 나옴.

2번

결과 : 원하던 대로 title과 일치하는 제목을 가진 글만 1개 나옴.
    // 제목
    if (title) {
      const feeds = await this.feedModel
        .find({ 'travelPlan.title': title })
        .populate('travelPlan')
        .exec();

      searchResult.push(...feeds);
    }
정확히 일치하는 결과가 1개만 나옴
 
이 이유는 다음과 같다.
이런식으로 find 메소드를 populate 앞에 붙이면 find가 개별 집합을 반환하고, populate도 문서에서 개별 집합을 반환하기 때문에 populate가 find에서 찾은 문서들을 필터링 하지 않는다.
그냥 find가 반환 배열 따로, populate가 반환한 배열 따로이고, populate는 나중에 반환한 배열에다가 find가 반환한 배열을 병합한다.
그리하여 내가 쓴 1번 코드는 find가 반환한 것만 나오게 된 것이다.
즉, find() 라고 썼으니 populate로 어떤 조건을 썼던 간에 모든 게시물이 조회되는 것이다.
본인은 find가 반환한 문서(document) 배열 안에서 populate가 그 안에서 필터링을 하는 줄 알았는데, 공식문서와 stackoverflow를 읽어보니까 그렇지 않다는 걸 알 수 있었다.
 

 

< Mongoose 공식 문서>

 

 

< Stackoverflow >

find() 메서드가 반환하는 초기 문서 집합에 대해 populate() 메서드가 실행되고,

 

populate()는 참조된 컬렉션에서 각 문서에 대한 개별적인 find 쿼리를 생성하고 실행한 다음
그 결과를 원래 문서에 다시 병합한다.

 

따라서 populate() 결과는 find() 결과와 결합되어 최종적으로 반환된다.

populate() 제외하고 쓴 결과

    // 제목
    if (title) {
      const feeds = await this.feedModel
        .find({ 'travelPlan.title': title })
        .exec();

      searchResult.push(...feeds);
    }
populate 없어도 잘 나옴.
find 메소드 다음에 populate를 쓰지 않아도 잘 검색이 된다.
스키마에서 이미 populate를 했기 때문에 쿼리에서 populate를 하지 않아도 됨.
그냥 find만 사용해서 조회만 하면 된다.
728x90