$unwind (집계)
정의
호환성
다음 환경에서 호스팅되는 배포에 $unwind
사용할 수 있습니다.
MongoDB Atlas: 클라우드에서의 MongoDB 배포를 위한 완전 관리형 서비스
MongoDB Enterprise: MongoDB의 구독 기반 자체 관리 버전
MongoDB Community: MongoDB의 소스 사용 가능 무료 자체 관리 버전
구문
필드 경로 피연산자 또는 문서 피연산자를 전달하여 배열 필드를 해제할 수 있습니다.
필드 경로 피연산자
배열 필드 경로를 $unwind
로 전달할 수 있습니다. 이 구문을 사용할 때 $unwind
는 필드 값이 null이거나 누락되었거나 빈 배열인 경우 문서를 출력하지 않습니다.
{ $unwind: <field path> }
필드 경로를 지정할 때 필드 이름 앞에 달러 기호 $
를 붙이고 따옴표로 묶습니다.
옵션이 있는 문서 피연산자
버전 3.2에 새로 추가되었습니다.
$unwind
에 문서를 전달하여 다양한 동작 옵션을 지정할 수 있습니다.
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
필드 | 유형 | 설명 |
---|---|---|
문자열 | 배열 필드의 필드 경로입니다. 필드 경로를 지정하려면 필드 이름 앞에 달러 기호 | |
문자열 | 선택 사항. 요소의 배열 인덱스를 저장할 새 필드의 이름입니다. 이름은 달러 기호 | |
부울 |
동작
Non-Array Field Path(비배열 필드 경로)
피연산자가 배열로 해석되지 않지만 누락되지 않았거나
null
또는 빈 배열인 경우$unwind
는 피연산자를 단일 요소 배열로 취급합니다.피연산자가
null
이거나, 누락되었거나, 빈 배열$unwind
인 경우 preserveNullAndEmptyArray 옵션에 설정된 동작을 따릅니다.
누락된 필드
입력 문서에 존재하지 않는 필드의 경로를 지정하거나 필드가 빈 배열인 경우 $unwind
는 기본적으로 입력 문서를 무시하고 해당 입력 문서에 대한 문서를 출력하지 않습니다.
버전 3.2의 새로운 기능: 배열 필드 가 누락되었거나 null 또는 빈 배열 이 있는 문서를 출력하려면 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
필드의 값을 제외하고 입력 문서와 동일합니다.
includeArrayIndex
개인정보 정책에 preserveNullAndEmptyArrays
버전 3.2에 새로 추가되었습니다.
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 } ])
다음 $unwind
연산은 이에 해당하며 sizes
필드 의 각 요소에 대한 문서 를 반환합니다. sizes
필드 가 배열 로 해석되지 않지만 누락되지 않았거나, null이거나 빈 배열 인 경우 $unwind
는 배열이 아닌 피연산자를 단일 요소 배열 로 처리합니다.
db.inventory2.aggregate( [ { $unwind: "$sizes" } ] ) db.inventory2.aggregate( [ { $unwind: { path: "$sizes" } } ] )
이 작업은 다음 문서를 반환합니다.
{ "_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" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }
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 }
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 }
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") }