MongoDB에서 중첩된 구조, 즉 배열 내부에 또 다른 배열이 있는 경우 특정 개수만큼 요소를 잘라내고 싶을 때가 있습니다. 이럴 때는 aggregate() 메서드와 함께 $slice 연산자를 사용하면 됩니다.
이 글에서는 실제 예제를 통해 배열 안의 배열을 슬라이스하는 방법을 단계별로 살펴보겠습니다.
1. 샘플 컬렉션 생성
먼저 문서가 포함된 컬렉션을 생성해 보겠습니다. 아래 예제에서는 Details 배열 안에 각 항목마다 다시 Subjects 배열이 들어 있는 중첩 구조를 사용합니다.
> db.demo111.insertOne(
... {
... "_id" : 101,
... "Name" : "Chris",
... "Details" : [
... {
... "_id" : 101,
... "Score" : 78,
... "Subjects" : [
... {
... "_id" : "10001",
... "SubjectName" : "MySQL"
... },
... {
... "_id" : "10003",
... "SubjectName" : "MongoDB"
... }
... ]
... },
... {
... "_id" : 102,
... "Score" : 87,
... "Subjects" : [
... {
... "_id" : "10004",
... "SubjectName" : "Java"
... }
... ]
... }
... ]
... }
... );
{ "acknowledged" : true, "insertedId" : 101 }2. 저장된 문서 확인하기
find() 메서드를 사용하면 컬렉션의 모든 문서를 조회할 수 있습니다.
> db.demo111.find();
위 명령은 다음과 같은 결과를 출력합니다.
{
"_id" : 101, "Name" : "Chris", "Details" : [
{ "_id" : 101, "Score" : 78, "Subjects" : [ { "_id" : "10001", "SubjectName" : "MySQL" },
{ "_id" : "10003", "SubjectName" : "MongoDB" } ] },
{ "_id" : 102, "Score" : 87, "Subjects" : [ { "_id" : "10004", "SubjectName" : "Java" } ] }
]
}3. 배열 내부의 배열을 슬라이스하는 쿼리
이제 집계 파이프라인을 작성해 보겠습니다. 여기서는 세 가지 연산자가 핵심 역할을 합니다.
- $addFields: 기존 필드를 새 값으로 대체하거나 추가할 때 사용합니다.
- $map:
Details배열의 각 요소를 순회하면서 변환 작업을 수행합니다. - $slice: 각 요소의
Subjects배열에서 원하는 개수(여기서는 1개)만 잘라냅니다.
> db.demo111.aggregate([
... { "$addFields": {
... "Details": {
... "$map": {
... "input": "$Details",
... "as": "out",
... "in": {
... "_id": "$$out._id",
... "Score": "$$out.Score",
... "Subjects": { "$slice": [ "$$out.Subjects", 1 ] }
... }
... }
... }
... }}
... ])쿼리를 실행하면 다음과 같은 결과가 출력됩니다.
{
"_id" : 101, "Name" : "Chris", "Details" : [
{ "_id" : 101, "Score" : 78, "Subjects" : [ { "_id" : "10001", "SubjectName" : "MySQL" } ] },
{ "_id" : 102, "Score" : 87, "Subjects" : [ { "_id" : "10004", "SubjectName" : "Java" } ] }
]
}결과 분석
실행 결과를 보면 첫 번째 Details 항목의 Subjects 배열이 기존에는 MySQL과 MongoDB 두 개의 과목을 담고 있었지만, $slice 덕분에 첫 번째 요소인 MySQL 하나만 남게 된 것을 확인할 수 있습니다.
이처럼 $addFields, $map, $slice를 조합하면 중첩 배열 구조에서도 원하는 깊이의 배열 요소를 손쉽게 제한할 수 있습니다. 참고로 $slice의 두 번째 인자 값을 변경하면 잘라낼 요소의 개수를 자유롭게 조절할 수 있으며, 음수를 사용하면 배열의 끝에서부터 요소를 가져올 수도 있습니다.