MongoDB에서 하위 문서(sub-document) 일치 조건을 기준으로 데이터를 정렬하려면 애그리게이션 프레임워크(aggregate)를 활용하는 것이 가장 효과적입니다. 일반적인 find() 메서드만으로는 배열 내부의 특정 요소 값을 기준으로 정렬하기 어렵기 때문입니다. 이번 글에서는 실제 예제를 통해 그 과정을 단계별로 살펴보겠습니다.
샘플 컬렉션 생성하기
먼저 학생 이름(StudentName)과 나이(Age), 점수(StudentScore)를 담은 하위 문서 배열(StudentDetails)로 구성된 컬렉션을 생성하고 문서 두 개를 삽입합니다.
> db.sortBySubDocumentsDemo.insertOne(
{
"StudentName": "Chris",
"StudentDetails": [
{
"Age":21,
"StudentScore":91
},
{
"Age":22,
"StudentScore":99
},
{
"Age":21,
"StudentScore":93
}
]
}
);
{
"acknowledged" : true,
"insertedId" : ObjectId("5cd57e297924bb85b3f48942")
}
> db.sortBySubDocumentsDemo.insertOne(
{
"StudentName": "Robert",
"StudentDetails": [
{
"Age":24,
"StudentScore":78
},
{
"Age":21,
"StudentScore":86
},
{
"Age":23,
"StudentScore":45
}
]
}
);
{
"acknowledged" : true,
"insertedId" : ObjectId("5cd57e4c7924bb85b3f48943")
}
저장된 문서 조회하기
find() 메서드를 사용하면 컬렉션에 저장된 모든 문서를 확인할 수 있습니다.
> db.sortBySubDocumentsDemo.find().pretty();
위 쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : ObjectId("5cd57e297924bb85b3f48942"),
"StudentName" : "Chris",
"StudentDetails" : [
{
"Age" : 21,
"StudentScore" : 91
},
{
"Age" : 22,
"StudentScore" : 99
},
{
"Age" : 21,
"StudentScore" : 93
}
]
}
{
"_id" : ObjectId("5cd57e4c7924bb85b3f48943"),
"StudentName" : "Robert",
"StudentDetails" : [
{
"Age" : 24,
"StudentScore" : 78
},
{
"Age" : 21,
"StudentScore" : 86
},
{
"Age" : 23,
"StudentScore" : 45
}
]
}하위 문서 일치 기준으로 정렬하는 쿼리
다음은 StudentDetails 배열에서 Age가 21인 하위 문서만 필터링한 후, StudentScore 값을 기준으로 오름차순 정렬하는 애그리게이션 쿼리입니다.
> db.sortBySubDocumentsDemo.aggregate([
{$match: { 'StudentDetails.Age': 21 }},
{$unwind: '$StudentDetails'},
{$match: {'StudentDetails.Age': 21}},
{$project: {_id: 0, "StudentName": 1, 'StudentDetails.StudentScore': 1}},
{$sort: { 'StudentDetails.StudentScore': 1 }},
{$limit: 5}
]);
애그리게이션 파이프라인 단계별 설명
- $match: Age가 21인 하위 문서를 포함한 문서만 우선 필터링합니다.
- $unwind: StudentDetails 배열을 개별 하위 문서 단위로 분해합니다.
- $match (재적용): 배열이 분해된 후 다시 한번 Age가 21인 요소만 남깁니다.
- $project: StudentName과 StudentDetails.StudentScore 필드만 선택하여 출력하고 _id는 제외합니다.
- $sort: StudentScore를 기준으로 오름차순(1) 정렬합니다.
- $limit: 최대 5개의 결과만 반환하도록 제한합니다.
쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{ "StudentName" : "Robert", "StudentDetails" : { "StudentScore" : 86 } }
{ "StudentName" : "Chris", "StudentDetails" : { "StudentScore" : 91 } }
{ "StudentName" : "Chris", "StudentDetails" : { "StudentScore" : 93 } }출력 결과를 보면 흥미로운 점을 확인할 수 있습니다. Chris의 점수(91, 93)가 Robert의 점수(86)보다 높지만, 정렬은 문서 전체가 아닌 개별 하위 문서 단위로 수행되기 때문에 Robert의 86점이 가장 먼저 나타납니다. 또한 Age가 21인 하위 문서는 전체 6개 중 3개뿐이므로 $limit을 5로 설정했더라도 실제로는 3개의 결과만 반환됩니다.