Computer >> 컴퓨터 >  >> 프로그래밍 >> MongoDB

MongoDB에서 중첩 배열을 집계하는 방법: aggregate() 완벽 가이드

MongoDB에서 중첩(nested) 배열을 집계하려면 aggregate() 메서드를 사용합니다. 이 글에서는 실제 예제를 통해 중첩 배열 안의 데이터를 조건에 따라 필터링하고, 새로운 필드로 출력하는 전체 과정을 단계별로 살펴보겠습니다.

1. 샘플 컬렉션 생성하기

먼저 insertOne() 메서드로 테스트용 문서를 삽입합니다. 이 문서는 'details' 배열 안에 'details1'이라는 배열이 한 번 더 중첩된 구조를 가지고 있습니다.

> db.demo441.insertOne(
...    {
...       "Name" : "David",
...       "Age" : 21,
...       "details" : [
...          {
...             "id" : 1,
...             "CountryName" : "US",
...             "details1" : [
...                {
...                   "SubjectName" : "MySQL",
...                   "Score":56
...                },
...                {
...                "SubjectName" : "MongoDB",
...                "Score":78
...                }
...             ]
...          }
...       ]
...    }
... );
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5e78cc05bbc41e36cc3caeb7")
}

위 코드는 학생 정보(Name, Age)와 함께 국가별 과목 점수 배열을 포함하는 문서를 생성합니다. 'details1' 배열에는 MySQL(56점)과 MongoDB(78점) 두 개의 과목 데이터가 들어 있습니다.

2. 저장된 문서 확인하기

find() 메서드를 사용하면 컬렉션의 모든 문서를 조회할 수 있습니다.

> db.demo441.find();

실행 결과는 다음과 같습니다.

{ "_id" : ObjectId("5e78cc05bbc41e36cc3caeb7"), "Name" : "David", "Age" : 21, "details" : [ { "id" : 1, "CountryName" : "US", "details1" : [ { "SubjectName" : "MySQL", "Score" : 56 }, { "SubjectName" : "MongoDB", "Score" : 78 } ] } ] }

3. 중첩 배열 집계 쿼리 작성하기

이제 핵심 단계입니다. 아래 쿼리는 $addFields, $map, $let, $arrayElemAt, $cond 연산자를 조합하여 중첩 배열을 처리합니다. 쿼리의 동작 방식은 다음과 같습니다.

  • $addFields: 기존 문서에 'ResultOfDetails'라는 새 필드를 추가합니다.
  • $map: 'details' 배열의 각 요소를 순회하며 변환 작업을 수행합니다.
  • $arrayElemAt (-1): 'details1' 배열의 마지막 요소를 가져옵니다.
  • $cond: 마지막 과목의 점수(Score)가 78점과 일치하는지 검사하고, 일치하면 해당 요소를 포함하고 그렇지 않으면 빈 배열을 반환합니다.
> db.demo441.aggregate([{
...    $addFields: {
...       ResultOfDetails: {
...          $map: {
...             input: "$details",
...             as: "output",
...             in: {
...                id: "$$output.id",
...                CountryName: "$$output.CountryName",
...                details1: {
...                   $let: {
...                      vars: {
...                         last: {
...                            $arrayElemAt: ["$$output.details1", -1]
...                         }
...                      },
...                      in: {
...                         $cond: [{
...                            $eq: ["$$last.Score", 78]
...                         },
...                         ["$$last"],
...                         []
...                       }
...                   }
...                }
...             }
...          }
...       }
...    }
... }]).pretty();

집계 결과

쿼리를 실행하면 다음과 같은 출력을 확인할 수 있습니다.

{
    "_id" : ObjectId("5e78cc05bbc41e36cc3caeb7"),
    "Name" : "David",
    "Age" : 21,
    "details" : [
       {
          "id" : 1,
          "CountryName" : "US",
          "details1" : [
             {
                "SubjectName" : "MySQL",
                "Score" : 56
             },
             {
                "SubjectName" : "MongoDB",
                "Score" : 78
             }
          ]
       }
    ],
    "ResultOfDetails" : [
       {
          "id" : 1,
          "CountryName" : "US",
          "details1" : [
             {
                "SubjectName" : "MongoDB",
                "Score" : 78
             }
          ]
       }  
    ]
}

결과를 보면 원본 'details' 필드는 그대로 유지되고, 새로 추가된 'ResultOfDetails' 필드에는 점수가 78점인 MongoDB 과목 데이터만 담긴 것을 확인할 수 있습니다. 이처럼 aggregate() 파이프라인과 배열 연산자를 조합하면 깊게 중첩된 배열 구조에서도 원하는 조건의 데이터만 손쉽게 추출할 수 있습니다.