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

MongoDB 집계에서 최대값과 일치하는 배열 요소를 추출하고 그룹화하는 방법

MongoDB 집계에서 최대값과 일치하는 배열 요소를 추출하고 그룹화하는 방법

MongoDB에서 배열에 담긴 여러 요소 중 최대값을 가진 항목을 찾아낸 뒤, 이를 기준으로 그룹화해야 하는 경우가 종종 있습니다. 이럴 때는 $group 연산자와 $max 연산자를 함께 활용하면 손쉽게 해결할 수 있습니다.

이번 글에서는 샘플 데이터를 직접 만들어 보고, 집계 파이프라인($project, $filter, $map, $arrayElemAt, $group)을 조합해 원하는 결과를 얻는 전 과정을 단계별로 살펴보겠습니다.

1단계: 컬렉션 생성 및 문서 삽입

먼저 demo510 컬렉션을 만들고 테스트용 문서 세 개를 삽입합니다. 각 문서는 Name(이름)과 Score(점수) 필드를 가진 객체 여러 개를 담고 있는 details 배열을 포함합니다.

> db.demo510.insertOne(
... {
...    details:[
...       {
...          Name:"Chris",
...          Score:56
...       },
...       {
...          Name:"David",
...          Score:45
...       }
...    ]
... }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e8845fa987b6e0e9d18f582")
}
> db.demo510.insertOne(
... {
...    details:[
...       {
...          Name:"Chris",
...          Score:56
...       },
...       {
...          Name:"David",
...          Score:47
...       }
...    ]
... }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e8845fb987b6e0e9d18f583")
}
> db.demo510.insertOne(
... {
...    details:[
...       {
...          Name:"Chris",
...          Score:45
...       },
...       {
...          Name:"David",
...          Score:91
...       }
...    ]
... }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e8845fb987b6e0e9d18f584")
}

2단계: find()로 저장된 문서 확인

find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 한눈에 확인할 수 있습니다.

> db.demo510.find();

위 명령을 실행하면 다음과 같은 출력 결과를 얻을 수 있습니다.

{ "_id" : ObjectId("5e8845fa987b6e0e9d18f582"), "details" : [ { "Name" : "Chris", "Score" : 56 },
{ "Name" : "David", "Score" : 45 } ] }
{ "_id" : ObjectId("5e8845fb987b6e0e9d18f583"), "details" : [ { "Name" : "Chris", "Score" : 56 },
{ "Name" : "David", "Score" : 47 } ] }
{ "_id" : ObjectId("5e8845fb987b6e0e9d18f584"), "details" : [ { "Name" : "Chris", "Score" : 45 },
{ "Name" : "David", "Score" : 91 } ] }

3단계: 집계 파이프라인으로 최대값 요소 추출 후 그룹화

이제 핵심인 집계 쿼리입니다. 아래 쿼리는 각 문서의 details 배열에서 Score가 가장 큰 요소만 걸러낸 다음, 해당 요소의 Name 값을 기준으로 그룹화하고 문서 수를 집계합니다.

각 연산자가 담당하는 역할을 정리하면 다음과 같습니다.

  • $map — details 배열에서 Score 값만 추출해 새로운 배열을 만듭니다.
  • $max — 추출한 점수 목록에서 최대값을 구합니다.
  • $filter — Score가 최대값과 일치하는 요소만 남깁니다.
  • $arrayElemAt — 필터링된 배열에서 첫 번째(인덱스 0) 요소를 선택합니다.
  • $group — Name을 기준으로 그룹화하고, $sum으로 문서 수를 계산합니다.
> db.demo510.aggregate([
... { "$project": {
...    "details": {
...       "$arrayElemAt": [
...          { "$filter": {
...             "input": "$details",
...             "as": "res",
...             "cond": {
...                "$eq": [
...                   "$$res.Score",
...                   { "$max": {
...                      "$map": {
...                         "input": "$details",
...                         "as": "out",
...                         "in": "$$out.Score"
...                      }
...                   }}
...                ]
...             }
...          }},
...          0
...       ]
...    }
... }},
... { "$group": {
...    "_id": "$details.Name",
...    "Name": { "$first": "$details.Name" },
...    "count": { "$sum": 1 }
... }}
... ])

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

{ "_id" : "David", "Name" : "David", "count" : 1 }
{ "_id" : "Chris", "Name" : "Chris", "count" : 2 }

결과 해석

출력 결과를 보면 David는 1건, Chris는 2건으로 집계되었습니다. 첫 번째와 두 번째 문서에서는 Chris의 점수(56)가 David의 점수(45, 47)보다 각각 높았고, 세 번째 문서에서는 David의 점수(91)가 Chris의 점수(45)보다 높았기 때문입니다. 즉, 이 쿼리는 문서별로 최고 점수를 기록한 사람을 뽑아낸 뒤, 이름별로 최고 점수를 차지한 횟수를 집계하는 것입니다.