$unwind (집계)
정의
호환성
다음 환경에서 호스팅되는 배포에 $unwind
사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
필드 경로 피연산자 또는 문서 피연산자를 전달하여 배열 필드를 해제할 수 있습니다.
필드 경로 피연산자
배열 필드 경로를 $unwind
로 전달할 수 있습니다. 이 구문을 사용할 때 $unwind
는 필드 값이 null이거나 누락되었거나 빈 배열인 경우 문서를 출력하지 않습니다.
{ $unwind: <field path> }
필드 경로를 지정할 때 필드 이름 앞에 달러 기호 $
를 붙이고 따옴표로 묶습니다.
옵션이 있는 문서 피연산자
$unwind
에 문서를 전달하여 다양한 동작 옵션을 지정할 수 있습니다.
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
필드 | 유형 | 설명 |
---|---|---|
문자열 | 배열 필드의 필드 경로입니다. 필드 경로를 지정하려면 필드 이름 앞에 달러 기호 | |
문자열 | 선택 사항. 요소의 배열 인덱스를 저장할 새 필드의 이름입니다. 이름은 달러 기호 | |
부울 |
동작
Non-Array Field Path(비배열 필드 경로)
피연산자가 배열로 해석되지 않지만 누락되지 않았거나
null
또는 빈 배열인 경우$unwind
는 피연산자를 단일 요소 배열로 취급합니다.피연산자가
null
이거나, 누락되었거나, 빈 배열$unwind
인 경우 preserveNullAndEmptyArray 옵션에 설정된 동작을 따릅니다.
누락된 필드
입력 문서에 존재하지 않는 필드의 경로를 지정하거나 필드가 빈 배열인 경우 $unwind
는 기본적으로 입력 문서를 무시하고 해당 입력 문서에 대한 문서를 출력하지 않습니다.
배열 필드가 누락되었거나, 널 또는 빈 배열이 있는 문서를 출력하려면 preserveNullAndEmptyArrays 옵션을 사용합니다.
예시
배열 Unwind
mongosh
에서 다음 문서를 사용하여 inventory
라는 이름의 샘플 컬렉션을 만듭니다.
db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
다음 집계는 $unwind
단계를 사용하여 sizes
배열의 각 요소에 대한 문서를 출력합니다.
db.inventory.aggregate( [ { $unwind : "$sizes" } ] )
이 연산은 다음과 같은 결과를 반환합니다.
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" } { "_id" : 1, "item" : "ABC1", "sizes" : "M" } { "_id" : 1, "item" : "ABC1", "sizes" : "L" }
각 문서는 이제 원래 sizes
배열의 값을 보유하는 sizes
필드의 값을 제외하고 입력 문서와 동일합니다.
누락되었거나 배열이 아닌 값
clothing
컬렉션을 살펴봅시다.
db.clothing.insertMany([ { "_id" : 1, "item" : "Shirt", "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "Shorts", "sizes" : [ ] }, { "_id" : 3, "item" : "Hat", "sizes": "M" }, { "_id" : 4, "item" : "Gloves" }, { "_id" : 5, "item" : "Scarf", "sizes" : null } ])
$unwind
는 sizes
필드를 단일 요소 배열로 취급합니다.
필드가 존재합니다,
값은 null이 아니며
값은 빈 배열이 아닙니다.
$unwind
를 사용하여 sizes
배열을 확장합니다.
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )
$unwind
작업은 다음을 반환합니다.
{ _id: 1, item: 'Shirt', sizes: 'S' }, { _id: 1, item: 'Shirt', sizes: 'M' }, { _id: 1, item: 'Shirt', sizes: 'L' }, { _id: 3, item: 'Hat', sizes: 'M' }
문서
"_id": 1
에서sizes
는 채워진 배열입니다.$unwind
는sizes
필드에 있는 각 요소에 대한 문서를 반환합니다.문서
"_id": 3
에서sizes
는 단일 요소 배열로 해석됩니다.sizes
필드를 단일 요소 배열로 축소할 수 없기 때문에 문서"_id": 2, "_id": 4
및"_id": 5
은 아무 것도 반환하지 않습니다.
참고
{ path: <FIELD> }
구문은 선택 사항입니다. 다음 $unwind
작업은 동일합니다.
db.clothing.aggregate( [ { $unwind: "$sizes" } ] ) db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )
preserveNullAndEmptyArrays
개인정보 정책에 includeArrayIndex
preserveNullAndEmptyArrays
및 includeArrayIndex
예시에서는 다음 컬렉션을 사용합니다.
db.inventory2.insertMany([ { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] }, { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" }, { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") }, { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null } ])
preserveNullAndEmptyArrays
다음 $unwind
작업은 preserveNullAndEmptyArrays 옵션을 사용하여 sizes
필드가 null이거나, 누락되었거나, 빈 배열인 문서를 포함합니다.
db.inventory2.aggregate( [ { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } } ] )
출력에는 sizes
필드가 null이거나 누락되었거나 빈 배열인 문서가 포함됩니다.
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" } { "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") } { "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null }
includeArrayIndex
다음 $unwind
연산은 includeArrayIndex 옵션을 사용하여 출력에 배열 인덱스를 포함합니다.
db.inventory2.aggregate( [ { $unwind: { path: "$sizes", includeArrayIndex: "arrayIndex" } }])
이 작업은 sizes
배열을 해제하고 새 arrayIndex
필드에 배열 색인을 포함합니다. sizes
필드가 채워진 배열로 확인되지 않지만 누락되거나 null이거나 빈 배열인 경우 arrayIndex
필드는 null
입니다.
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S", "arrayIndex" : NumberLong(0) } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M", "arrayIndex" : NumberLong(1) } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L", "arrayIndex" : NumberLong(2) } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M", "arrayIndex" : null }
Unwound 값으로 그룹화
mongosh
에서 다음 문서를 사용하여 inventory2
라는 이름의 샘플 컬렉션을 만듭니다.
db.inventory2.insertMany([ { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] }, { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" }, { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") }, { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null } ])
다음 파이프라인은 sizes
배열을 해제하고 해제된 크기 값을 기준으로 결과 문서를 그룹화합니다.
db.inventory2.aggregate( [ // First Stage { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }, // Second Stage { $group: { _id: "$sizes", averagePrice: { $avg: "$price" } } }, // Third Stage { $sort: { "averagePrice": -1 } } ] )
- 첫 번째 단계:
$unwind
단계는sizes
배열의 각 요소에 대해 새 문서를 출력합니다. 이 단계에서는 preserveNullAndEmptyArrays 옵션을 사용하여sizes
필드가 누락되었거나, null이거나, 빈 배열이 있는 문서를 출력에 포함합니다. 이 단계에서는 아래 문서를 다음 단계로 전달합니다.{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" } { "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") } { "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null } - 두 번째 단계:
$group
단계에서는sizes
만큼 문서를 그룹화하고 각 크기의 평균 가격을 계산합니다. 이 단계에서는 다음 문서를 다음 단계로 전달합니다.{ "_id" : "S", "averagePrice" : NumberDecimal("80") } { "_id" : "L", "averagePrice" : NumberDecimal("80") } { "_id" : "M", "averagePrice" : NumberDecimal("120") } { "_id" : null, "averagePrice" : NumberDecimal("45.25") } - 세 번째 단계:
$sort
단계에서는 문서를 내림차순으로averagePrice
씩 정렬합니다. 이 연산은 다음과 같은 결과를 반환합니다.{ "_id" : "M", "averagePrice" : NumberDecimal("120") } { "_id" : "L", "averagePrice" : NumberDecimal("80") } { "_id" : "S", "averagePrice" : NumberDecimal("80") } { "_id" : null, "averagePrice" : NumberDecimal("45.25") }
임베디드 배열 풀기
mongosh
에서 다음 문서를 사용하여 sales
라는 이름의 샘플 컬렉션을 만듭니다.
db.sales.insertMany([ { _id: "1", "items" : [ { "name" : "pens", "tags" : [ "writing", "office", "school", "stationary" ], "price" : NumberDecimal("12.00"), "quantity" : NumberInt("5") }, { "name" : "envelopes", "tags" : [ "stationary", "office" ], "price" : NumberDecimal("19.95"), "quantity" : NumberInt("8") } ] }, { _id: "2", "items" : [ { "name" : "laptop", "tags" : [ "office", "electronics" ], "price" : NumberDecimal("800.00"), "quantity" : NumberInt("1") }, { "name" : "notepad", "tags" : [ "stationary", "school" ], "price" : NumberDecimal("14.95"), "quantity" : NumberInt("3") } ] } ])
다음 작업은 태그별로 판매된 품목을 그룹화하고 각 태그당 총 판매량을 계산합니다.
db.sales.aggregate([ // First Stage { $unwind: "$items" }, // Second Stage { $unwind: "$items.tags" }, // Third Stage { $group: { _id: "$items.tags", totalSalesAmount: { $sum: { $multiply: [ "$items.price", "$items.quantity" ] } } } } ])
- 첫 번째 단계
첫 번째
$unwind
단계는items
배열의 각 요소에 맞게 새 문서를 출력합니다.{ "_id" : "1", "items" : { "name" : "pens", "tags" : [ "writing", "office", "school", "stationary" ], "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : [ "stationary", "office" ], "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : [ "office", "electronics" ], "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : [ "stationary", "school" ], "price" : NumberDecimal("14.95"), "quantity" : 3 } } - 두 번째 단계
두 번째
$unwind
단계에서는items.tags
배열의 각 요소에 대해 새 문서를 출력합니다.{ "_id" : "1", "items" : { "name" : "pens", "tags" : "writing", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "office", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "school", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "stationary", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : "stationary", "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : "office", "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : "office", "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : "electronics", "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : "stationary", "price" : NumberDecimal("14.95"), "quantity" : 3 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : "school", "price" : NumberDecimal("14.95"), "quantity" : 3 } } - 세 번째 단계
$group
단계에서는 문서를 태그별로 그룹화하고 각 태그가 있는 항목의 총 판매 금액을 계산합니다.{ "_id" : "writing", "totalSalesAmount" : NumberDecimal("60.00") } { "_id" : "stationary", "totalSalesAmount" : NumberDecimal("264.45") } { "_id" : "electronics", "totalSalesAmount" : NumberDecimal("800.00") } { "_id" : "school", "totalSalesAmount" : NumberDecimal("104.85") } { "_id" : "office", "totalSalesAmount" : NumberDecimal("1019.60") }