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

MongoDB에서 중첩 배열의 모든 요소가 조건과 일치하는 객체만 필터링하는 방법


aggregate()로 조건 일치 객체 필터링하기

중첩 배열의 모든 요소가 특정 조건과 일치하는 객체를 필터링하려면 MongoDB의 aggregate() 메서드를 사용해야 합니다. 먼저 예제에 사용할 문서들이 담긴 컬렉션을 생성해 보겠습니다.

> db.demo418.insertOne(
...    {
...       "details":[
...          {
...             "CountryName":"US",
...             "Marks":45
...          },
...          {
...             "CountryName":"US",
...             "Marks":56
...          },
...
...       ],
...       "Name":"John"
...    }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e724324b912067e57771ae6")
}
> db.demo418.insertOne(
...    {
...       "details":[
...          {
...             "CountryName":"US",
...             "Marks":78
...          },
...          {
...             "CountryName":"UK",
...             "Marks":97
...          },
...
...       ],
...       "Name":"Mike"
...    }
... );
{
   "acknowledged" : true,
   "insertedId" : ObjectId("5e724325b912067e57771ae7")
}

위 코드는 두 개의 문서를 생성합니다. 첫 번째 문서(John)의 details 배열에는 CountryName이 모두 "US"인 요소 두 개가 있고, 두 번째 문서(Mike)의 배열에는 "US"와 "UK"가 섞여 있어 이후 필터링 결과를 비교하기 좋은 구조입니다.

find()로 전체 문서 확인하기

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

> db.demo418.find();

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

{ "_id" : ObjectId("5e724324b912067e57771ae6"), "details" : [ { "CountryName" : "US", "Marks" : 45 }, { "CountryName" : "US", "Marks" : 56 } ], "Name" : "John" }
{ "_id" : ObjectId("5e724325b912067e57771ae7"), "details" : [ { "CountryName" : "US", "Marks" : 78 }, { "CountryName" : "UK", "Marks" : 97 } ], "Name" : "Mike" }

배열의 모든 요소가 조건과 일치하는 문서 필터링 쿼리

다음은 중첩 배열(details)의 모든 요소가 조건(CountryName이 "US")과 일치하는 문서만 걸러내는 집계 쿼리입니다.

> db.demo418.aggregate([
...    {$unwind:"$details"},
...    { $group: {
...       _id: '$_id',
...       details : { $first: '$details' },
...       alldetails: { $sum: 1 },
...       alldetailsmatch: { $sum: { $cond: [ { $eq: [ '$details.CountryName', "US" ] }, 1, 0 ] } },
... Name: { $first: '$Name' }
... }},
... { $project: {
...    _id: 1,
...    Name: 1,
...    details: 1,
...    arrayValue: { $cond: [ { $eq: [ '$alldetails', '$alldetailsmatch' ] }, 1, 0 ] }
...    }},
... { $match: { 'arrayValue' : 1 } }
... ])

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

{ "_id" : ObjectId("5e724324b912067e57771ae6"), "details" : { "CountryName" : "US", "Marks" : 45 }, "Name" : "John", "arrayValue" : 1 }

쿼리 동작 원리

이 집계 파이프라인은 다음 단계를 거쳐 동작합니다.

  • $unwind: details 배열을 개별 문서 단위로 분해합니다.
  • $group: _id를 기준으로 재그룹화하면서 전체 배열 요소 수(alldetails)와 CountryName이 "US"인 요소 수(alldetailsmatch)를 각각 집계합니다.
  • $project: 두 값이 서로 같으면 arrayValue를 1로, 하나라도 다르면 0으로 설정합니다.
  • $match: arrayValue가 1인 문서, 즉 배열의 모든 요소가 조건을 충족하는 문서만 최종 결과로 출력합니다.

결과적으로 "UK"인 요소를 하나라도 포함하고 있는 Mike의 문서는 제외되고, 배열 내 모든 국가명이 "US"인 John의 문서만 반환됩니다. 이처럼 $unwind, $group, $cond를 조합하면 중첩 배열 전체가 특정 조건을 만족하는지 손쉽게 검증할 수 있습니다.