MongoDB에서 중첩된 문서의 하위 필드(subfield)를 쿼리 결과의 최상위 레벨로 끌어올리고 싶을 때가 있습니다. 이때 모든 키 이름을 하나하나 나열하지 않고 처리하려면 애그리게이션 파이프라인의 $objectToArray와 $arrayToObject 연산자를 활용하면 됩니다.
테스트용 컬렉션 생성
먼저 예제에 사용할 컬렉션을 만들고 문서를 삽입해 보겠습니다.
> db.promoteSubfieldsDemo.insertOne({'s':10,'y':{'t':20,'u':30}});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e038004190a577c668b55d5")
}저장된 문서 확인하기
find() 메서드를 사용해 컬렉션의 모든 문서를 조회합니다.
> db.promoteSubfieldsDemo.find().pretty();
실행 결과는 다음과 같습니다. y 필드 안에 t와 u라는 하위 필드가 중첩되어 있는 것을 확인할 수 있습니다.
{
"_id" : ObjectId("5e038004190a577c668b55d5"),
"s" : 10,
"y" : {
"t" : 20,
"u" : 30
}
}하위 필드를 최상위 레벨로 끌어올리는 쿼리
모든 키를 직접 나열하지 않고 하위 필드를 최상위 레벨로 승격하려면 아래와 같이 $replaceRoot, $concatArrays, $objectToArray, $arrayToObject를 조합한 애그리게이션 쿼리를 사용합니다.
> db.promoteSubfieldsDemo.aggregate([
... { "$replaceRoot": {
... "newRoot": {
... "$arrayToObject": {
... "$concatArrays": [
... [{ "k": "s", "v": "$s" }],
... { "$objectToArray": "$y" }
... ]
... }
... }
... }}
... ]);쿼리 동작 원리
- $objectToArray:
y객체를{ k: 키, v: 값 }형태의 배열로 변환합니다. - $concatArrays: 기존 최상위 필드(
s)를 배열 형태로 만든 것과 위에서 변환한 배열을 하나로 합칩니다. - $arrayToObject: 합쳐진 배열을 다시 단일 객체(문서)로 변환합니다.
- $replaceRoot: 변환된 새 문서를 결과의 루트로 지정합니다.
이 쿼리를 실행하면 다음과 같은 출력 결과를 얻을 수 있습니다. 하위 필드였던 t와 u가 최상위 레벨로 끌어올려진 것을 확인할 수 있습니다.
{ "s" : 10, "t" : 20, "u" : 30 }정리
이 방식의 가장 큰 장점은 하위 문서의 키가 무엇인지 미리 알지 못해도 된다는 점입니다. 키가 동적으로 추가되거나 변경되더라도 $objectToArray가 자동으로 전체 키-값 쌍을 배열로 변환해 주기 때문에, 별도의 유지보수 없이 유연하게 하위 필드를 최상위 레벨로 승격할 수 있습니다.