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

MongoDB 집계(Aggregation)로 배열 안의 배열 슬라이스하기

MongoDB에서 중첩된 구조, 즉 배열 내부에 또 다른 배열이 있는 경우 특정 개수만큼 요소를 잘라내고 싶을 때가 있습니다. 이럴 때는 aggregate() 메서드와 함께 $slice 연산자를 사용하면 됩니다.

이 글에서는 실제 예제를 통해 배열 안의 배열을 슬라이스하는 방법을 단계별로 살펴보겠습니다.

1. 샘플 컬렉션 생성

먼저 문서가 포함된 컬렉션을 생성해 보겠습니다. 아래 예제에서는 Details 배열 안에 각 항목마다 다시 Subjects 배열이 들어 있는 중첩 구조를 사용합니다.

> db.demo111.insertOne(
...     {
...        "_id" : 101,
...        "Name" : "Chris",
...        "Details" : [
...           {
...              "_id" : 101,
...              "Score" : 78,
...              "Subjects" : [
...                 {
...                    "_id" : "10001",
...                    "SubjectName" : "MySQL"
...                 },
...                 {
...                    "_id" : "10003",
...                    "SubjectName" : "MongoDB"
...                 }
...              ]
...           },
...           {
...              "_id" : 102,
...              "Score" : 87,
...              "Subjects" : [
...                 {
...                    "_id" : "10004",
...                    "SubjectName" : "Java"
...                 }
...              ]
...           }
...        ]
...    }
... );
{ "acknowledged" : true, "insertedId" : 101 }

2. 저장된 문서 확인하기

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

> db.demo111.find();

위 명령은 다음과 같은 결과를 출력합니다.

{
   "_id" : 101, "Name" : "Chris", "Details" : [
      { "_id" : 101, "Score" : 78, "Subjects" : [ { "_id" : "10001", "SubjectName" : "MySQL" },
      { "_id" : "10003", "SubjectName" : "MongoDB" } ] },
      { "_id" : 102, "Score" : 87, "Subjects" : [ { "_id" : "10004", "SubjectName" : "Java" } ] }
   ]
}

3. 배열 내부의 배열을 슬라이스하는 쿼리

이제 집계 파이프라인을 작성해 보겠습니다. 여기서는 세 가지 연산자가 핵심 역할을 합니다.

  • $addFields: 기존 필드를 새 값으로 대체하거나 추가할 때 사용합니다.
  • $map: Details 배열의 각 요소를 순회하면서 변환 작업을 수행합니다.
  • $slice: 각 요소의 Subjects 배열에서 원하는 개수(여기서는 1개)만 잘라냅니다.
> db.demo111.aggregate([
...    { "$addFields": {
...       "Details": {
...          "$map": {
...             "input": "$Details",
...             "as": "out",
...             "in": {
...                "_id": "$$out._id",
...                "Score": "$$out.Score",
...                "Subjects": { "$slice": [ "$$out.Subjects", 1 ] }
...             }
...          }
...       }
...    }}
... ])

쿼리를 실행하면 다음과 같은 결과가 출력됩니다.

{
   "_id" : 101, "Name" : "Chris", "Details" : [
      { "_id" : 101, "Score" : 78, "Subjects" : [ { "_id" : "10001", "SubjectName" : "MySQL" } ] },
      { "_id" : 102, "Score" : 87, "Subjects" : [ { "_id" : "10004", "SubjectName" : "Java" } ] }
   ]
}

결과 분석

실행 결과를 보면 첫 번째 Details 항목의 Subjects 배열이 기존에는 MySQL과 MongoDB 두 개의 과목을 담고 있었지만, $slice 덕분에 첫 번째 요소인 MySQL 하나만 남게 된 것을 확인할 수 있습니다.

이처럼 $addFields, $map, $slice를 조합하면 중첩 배열 구조에서도 원하는 깊이의 배열 요소를 손쉽게 제한할 수 있습니다. 참고로 $slice의 두 번째 인자 값을 변경하면 잘라낼 요소의 개수를 자유롭게 조절할 수 있으며, 음수를 사용하면 배열의 끝에서부터 요소를 가져올 수도 있습니다.