MongoDB에서 중첩된 배열 문서 내부의 특정 필드만 가져오고 싶을 때는 집계 파이프라인의 $filter와 $project 연산자를 함께 사용하면 됩니다. 이 방법을 단계별로 살펴보겠습니다.
1. 샘플 컬렉션 생성
먼저 실습에 사용할 컬렉션과 문서를 생성합니다. 아래 예제는 details1 → details2 → details3로 이어지는 다층 구조의 중첩 배열을 포함하고 있습니다.
> db.demo342.insertOne({
... "Id": "101",
... "details1" : {
... "details2" : [
... {
... "details3" : [
... {
... "Name": "Mike",
... "CountryName" : "US"
... },
... {
... "Name": "David",
... "CountryName" : "AUS"
... },
... {
... "Name": "Bob",
... "CountryName" : "UK"
... }
... ]
... }
... ]
... }
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5e53ef99f8647eb59e5620a9")
}2. 전체 문서 확인하기
find() 메서드를 사용해 컬렉션의 모든 문서를 조회해 보겠습니다.
> db.demo342.find();
위 쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{ "_id" : ObjectId("5e53ef99f8647eb59e5620a9"), "Id" : "101", "details1" : { "details2" : [ { "details3" : [ { "Name" : "Mike", "CountryName" : "US" }, { "Name" : "David", "CountryName" : "AUS" }, { "Name" : "Bob", "CountryName" : "UK" } ] } ] } }현재는 details3 배열 안의 모든 요소(Mike, David, Bob)가 함께 반환되는 것을 확인할 수 있습니다.
3. $filter와 $project로 특정 필드만 추출하기
이제 중첩 배열에서 조건에 맞는 특정 요소만 남기고 나머지는 제거하는 쿼리를 작성해 보겠습니다. 여기서는 Name이 "Bob"인 문서만 추출하는 것을 목표로 합니다.
핵심 로직은 다음과 같습니다.
- $map: details2 배열의 각 요소를 순회하며 내부의 details3 배열을 처리합니다.
- $filter (내부): details3 배열에서 Name이 "Bob"과 일치하는 요소만 남깁니다.
- $filter (외부): details3가 빈 배열이 된 details2 요소는 제거하여 불필요한 빈 구조가 남지 않도록 합니다.
- $project: 최종적으로 원하는 필드 구조만 출력합니다.
> db.demo342.aggregate([
... { "$project": {
... "details1": {
... "details2": {
... "$filter": {
... "input": {
... "$map": {
... "input": "$details1.details2",
... "in": {
... "details3": {
... "$filter": {
... "input": "$$this.details3",
... "cond": { "$eq": ["$$this.Name", "Bob"] }
... }
... }
... }
... }
... },
... "cond": { "$ne": ["$$this.details3", []] }
... }
... }
... }
... }}
... ])4. 실행 결과 확인
위 집계 쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{ "_id" : ObjectId("5e53ef99f8647eb59e5620a9"), "details1" : { "details2" : [ { "details3" : [ { "Name" : "Bob", "CountryName" : "UK" } ] } ] } }정리
이처럼 $project로 출력할 필드 구조를 정의하고, $map으로 배열을 순회한 뒤, $filter의 cond 조건으로 원하는 값만 걸러내면 중첩 배열 깊숙이 있는 특정 필드만 정확하게 추출할 수 있습니다. 외부 $filter에서 빈 배열([])을 제외하는 조건을 추가하면 조건에 맞지 않는 요소까지 깔끔하게 제거되어 더욱 효율적인 결과를 얻을 수 있습니다.