MongoDB에서 배열 안에 여러 개의 하위 문서가 포함된 중첩(nested) 구조를 다루다 보면, 각 문서에 실제로 어떤 필드(키)가 존재하는지 값 없이 키 이름만 확인하고 싶은 경우가 있습니다. 이번 글에서는 애그리게이션 파이프라인의 $reduce, $map, $objectToArray 연산자를 조합하여 중첩 문서의 키 목록만 깔끔하게 추출하는 방법을 알아보겠습니다.
1. 샘플 컬렉션 생성하기
먼저 데모용 컬렉션을 만들고 문서를 하나 삽입합니다. details 필드는 두 개의 하위 문서를 담고 있는 배열이며, 두 번째 문서에는 isMarried라는 추가 키가 있다는 점에 주목하세요.
> db.demo740.insertOne({
... "details":
... [
... {
... Name:"Chris",
... Age:21,
... CountryName:"US"
... },
... {
... Name:"Bob",
... Age:20,
... CountryName:"UK",
... isMarried:true
... }
... ]
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5ead700c57bb72a10bcf066d")
}
2. 저장된 문서 확인하기
find() 메서드를 사용해 컬렉션의 모든 문서를 조회해 보겠습니다.
> db.demo740.find();
위 명령을 실행하면 다음과 같은 결과가 출력됩니다.
"_id" : ObjectId("5ead700c57bb72a10bcf066d"), "details" : [ { "Name" : "Chris", "Age" : 21, "CountryName" : "US" }, { "Name" : "Bob", "Age" : 20, "CountryName" : "UK", "isMarried" : true } ] }
3. 중첩 문서의 키만 추출하는 쿼리
다음은 애그리게이션 파이프라인을 사용해 details 배열 내 모든 하위 문서의 키를 하나의 배열로 모아 반환하는 쿼리입니다.
> db.demo740.aggregate([
... {
... $project: {
... ListKeys: {
... $reduce: {
... input: "$details",
... initialValue: [],
... in: {
... $concatArrays: [
... "$$value",
... {
... $map: {
... input: {
... $objectToArray: "$$this"
... },
... in: "$$this.k"
... }
... }
... ]
... }
... }
... }
... }
... }
... ]).pretty()
쿼리 동작 원리
- $objectToArray: 각 하위 문서를
{k: 키, v: 값}형태의 요소로 이루어진 배열로 변환합니다. - $map: 변환된 배열에서
k(키 이름)만 뽑아 새로운 배열을 만듭니다. - $reduce + $concatArrays: 배열의 각 요소를 순회하면서 추출된 키 배열들을 하나의 배열로 누적 병합합니다.
4. 실행 결과
쿼리를 실행하면 다음과 같이 중첩 문서에 포함된 모든 키가 하나의 배열로 출력됩니다.
{
"_id" : ObjectId("5ead700c57bb72a10bcf066d"),
"ListKeys" : [
"Name",
"Age",
"CountryName",
"Name",
"Age",
"CountryName",
"isMarried"
]
}
결과를 보면 첫 번째 하위 문서의 키(Name, Age, CountryName)와 두 번째 하위 문서의 키(Name, Age, CountryName, isMarried)가 모두 포함되어 있습니다. 만약 중복 없이 고유한 키 목록만 필요하다면, 이 결과 뒤에 $unwind와 $group 단계를 추가하거나 클라이언트 측에서 중복을 제거하면 됩니다.