Docs Menu
Docs Home
/
데이터베이스 매뉴얼
/ / /

$unwind (집계)

$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>
}
}
필드
유형
설명

문자열

배열 필드의 필드 경로입니다. 필드 경로를 지정하려면 필드 이름 앞에 달러 기호 $를 붙이고 따옴표로 묶습니다.

문자열

선택 사항. 요소의 배열 인덱스를 저장할 새 필드의 이름입니다. 이름은 달러 기호 $로 시작할 수 없습니다.

부울

선택 사항.

  • true, 이 path null이거나 누락되었거나 빈 배열 인$unwind 경우 는 문서 출력합니다.

  • false,path 이 null이거나 누락되었거나 빈 배열 인$unwind 경우 는 문서 출력하지 않습니다.

기본값은 false입니다.

  • 피연산자가 배열로 해석되지 않지만 누락되지 않았거나 null 또는 빈 배열인 경우 $unwind는 피연산자를 단일 요소 배열로 취급합니다.

  • 피연산자가 null이거나, 누락되었거나, 빈 배열 $unwind 인 경우 preserveNullAndEmptyArray 옵션에 설정된 동작을 따릅니다.

입력 문서에 존재하지 않는 필드의 경로를 지정하거나 필드가 빈 배열인 경우 $unwind는 기본적으로 입력 문서를 무시하고 해당 입력 문서에 대한 문서를 출력하지 않습니다.

배열 필드가 누락되었거나, 널 또는 빈 배열이 있는 문서를 출력하려면 preserveNullAndEmptyArrays 옵션을 사용합니다.

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 }
])

$unwindsizes 필드를 단일 요소 배열로 취급합니다.

  • 필드가 존재합니다,

  • 값은 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 는 채워진 배열입니다. $unwindsizes 필드에 있는 각 요소에 대한 문서를 반환합니다.

  • 문서 "_id": 3에서 sizes는 단일 요소 배열로 해석됩니다.

  • sizes 필드를 단일 요소 배열로 축소할 수 없기 때문에 문서 "_id": 2, "_id": 4"_id": 5은 아무 것도 반환하지 않습니다.

참고

{ path: <FIELD> } 구문은 선택 사항입니다. 다음 $unwind 작업은 동일합니다.

db.clothing.aggregate( [ { $unwind: "$sizes" } ] )
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )

preserveNullAndEmptyArraysincludeArrayIndex 예시에서는 다음 컬렉션을 사용합니다.

db.inventory2.insertMany([
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: [ "S", "M", "L"] },
{ _id: 2, item: "EFG", price: Decimal128("120"), sizes: [ ] },
{ _id: 3, item: "IJK", price: Decimal128("160"), sizes: "M" },
{ _id: 4, item: "LMN" , price: Decimal128("10") },
{ _id: 5, item: "XYZ", price: Decimal128("5.75"), sizes: null }
])

다음 $unwind 작업은 preserveNullAndEmptyArrays 옵션을 사용하여 sizes 필드가 null이거나, 누락되었거나, 빈 배열인 문서를 포함합니다.

db.inventory2.aggregate( [
{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }
] )

출력에는 sizes 필드가 null이거나 누락되었거나 빈 배열인 문서가 포함됩니다.

{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "S" }
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "M" }
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "L" }
{ _id: 2, item: "EFG", price: Decimal128("120") }
{ _id: 3, item: "IJK", price: Decimal128("160"), sizes: "M" }
{ _id: 4, item: "LMN", price: Decimal128("10") }
{ _id: 5, item: "XYZ", price: Decimal128("5.75"), sizes: null }

다음 $unwind 연산은 includeArrayIndex 옵션을 사용하여 출력에 배열 인덱스를 포함합니다.

db.inventory2.aggregate( [
{
$unwind:
{
path: "$sizes",
includeArrayIndex: "arrayIndex"
}
}])

이 작업은 sizes 배열을 해제하고 새 arrayIndex 필드에 배열 색인을 포함합니다. sizes 필드가 채워진 배열로 확인되지 않지만 누락되거나 null이거나 빈 배열인 경우 arrayIndex 필드는 null입니다.

{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "S", arrayIndex: Long(0) }
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "M", arrayIndex: Long(1) }
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "L", arrayIndex: Long(2) }
{ _id: 3, item: "IJK", price: Decimal128("160"), sizes: "M", arrayIndex: null }

mongosh에서 다음 문서를 사용하여 inventory2라는 이름의 샘플 컬렉션을 만듭니다.

db.inventory2.insertMany([
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: [ "S", "M", "L"] },
{ _id: 2, item: "EFG", price: Decimal128("120"), sizes: [ ] },
{ _id: 3, item: "IJK", price: Decimal128("160"), sizes: "M" },
{ _id: 4, item: "LMN" , price: Decimal128("10") },
{ _id: 5, item: "XYZ", price: Decimal128("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: Decimal128("80"), sizes: "S" }
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "M" }
{ _id: 1, item: "ABC", price: Decimal128("80"), sizes: "L" }
{ _id: 2, item: "EFG", price: Decimal128("120") }
{ _id: 3, item: "IJK", price: Decimal128("160"), sizes: "M" }
{ _id: 4, item: "LMN", price: Decimal128("10") }
{ _id: 5, item: "XYZ", price: Decimal128("5.75"), sizes: null }
두 번째 단계:

$group 단계에서는 sizes만큼 문서를 그룹화하고 각 크기의 평균 가격을 계산합니다. 이 단계에서는 다음 문서를 다음 단계로 전달합니다.

{ _id: "S", averagePrice: Decimal128("80") }
{ _id: "L", averagePrice: Decimal128("80") }
{ _id: "M", averagePrice: Decimal128("120") }
{ _id: null, averagePrice: Decimal128("45.25") }
세 번째 단계:

$sort 단계에서는 문서를 내림차순으로 averagePrice씩 정렬합니다. 이 연산은 다음과 같은 결과를 반환합니다.

{ _id : "M", averagePrice: Decimal128("120") }
{ _id : "L", averagePrice: Decimal128("80") }
{ _id : "S", averagePrice: Decimal128("80") }
{ _id : null, averagePrice: Decimal128("45.25") }

mongosh에서 다음 문서를 사용하여 sales라는 이름의 샘플 컬렉션을 만듭니다.

db.sales.insertMany( [
{
_id: "1",
items: [
{
name: "pens",
tags: [ "writing", "office", "school", "stationary" ],
price: Decimal128("12.00"),
quantity: Int32("5")
},
{
name: "envelopes",
tags: [ "stationary", "office" ],
price: Decimal128("19.95"),
quantity: Int32("8")
}
]
},
{
_id: "2",
items: [
{
name: "laptop",
tags: [ "office", "electronics" ],
price: Decimal128("800.00"),
quantity: Int32("1")
},
{
name: "notepad",
tags: [ "stationary", "school" ],
price: Decimal128("14.95"),
quantity: Int32("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: Decimal128("12.00"), quantity: 5 } }
{ _id: "1", items: { name: "envelopes", tags: [ "stationary", "office" ], price: Decimal128("19.95"), quantity: 8 } }
{ _id: "2", items: { name: "laptop", tags: [ "office", "electronics" ], price: Decimal128("800.00"), quantity": 1 } }
{ _id: "2", items: { name: "notepad", tags: [ "stationary", "school" ], price: Decimal128("14.95"), quantity: 3 } }
두 번째 단계

두 번째 $unwind 단계에서는 items.tags 배열의 각 요소에 대해 새 문서를 출력합니다.

{ _id: "1", items: { name: "pens", tags: "writing", price: Decimal128("12.00"), quantity: 5 } }
{ _id: "1", items: { name: "pens", tags: "office", price: Decimal128("12.00"), quantity: 5 } }
{ _id: "1", items: { name: "pens", tags: "school", price: Decimal128("12.00"), quantity: 5 } }
{ _id: "1", items: { name: "pens", tags: "stationary", price: Decimal128("12.00"), quantity: 5 } }
{ _id: "1", items: { name: "envelopes", tags: "stationary", price: Decimal128("19.95"), quantity: 8 } }
{ _id: "1", items: { name: "envelopes", tags: "office", "price" : Decimal128("19.95"), quantity: 8 } }
{ _id: "2", items: { name: "laptop", tags: "office", price: Decimal128("800.00"), quantity: 1 } }
{ _id: "2", items: { name: "laptop", tags: "electronics", price: Decimal128("800.00"), quantity: 1 } }
{ _id: "2", items: { name: "notepad", tags: "stationary", price: Decimal128("14.95"), quantity: 3 } }
{ _id: "2", items: { name: "notepad", "ags: "school", price: Decimal128("14.95"), quantity: 3 } }
세 번째 단계

$group 단계에서는 문서를 태그별로 그룹화하고 각 태그가 있는 항목의 총 판매 금액을 계산합니다.

{ _id: "writing", totalSalesAmount: Decimal128("60.00") }
{ _id: "stationary", totalSalesAmount: Decimal128("264.45") }
{ _id: "electronics", totalSalesAmount: Decimal128("800.00") }
{ _id: "school", totalSalesAmount: Decimal128("104.85") }
{ _id: "office", totalSalesAmount: Decimal128("1019.60") }

이 페이지의 C# 예제에서는 Atlas 샘플 데이터 세트sample_mflix 데이터베이스 사용합니다. 무료 MongoDB Atlas cluster 생성하고 샘플 데이터 세트를 로드하는 방법을 학습하려면 MongoDB .NET/ C# 드라이버 문서에서 시작하기 를 참조하세요.

다음 Movie 클래스는 sample_mflix.movies 컬렉션의 문서를 모델링합니다.

public class Movie
{
public ObjectId Id { get; set; }
public int Runtime { get; set; }
public string Title { get; set; }
public string Rated { get; set; }
public List<string> Genres { get; set; }
public string Plot { get; set; }
public ImdbData Imdb { get; set; }
public int Year { get; set; }
public int Index { get; set; }
public string[] Comments { get; set; }
[BsonElement("lastupdated")]
public DateTime LastUpdated { get; set; }
}

참고

파스칼 케이스용 ConventionPack

이 페이지의 C# 클래스는 속성 이름에 파스칼식 대소문자를 사용하지만 MongoDB 컬렉션 의 필드 이름은 카멜식 대소문자를 사용합니다. 이러한 차이를 해소하기 위해 애플리케이션 시작될 때 다음 코드를 사용하여 ConventionPack 를 등록할 수 있습니다.

var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

MongoDB .NET/ C# 운전자 사용하여 $unwind 집계 파이프라인 에 단계를 추가하려면 PipelineDefinition 객체 에서 Unwind() 메서드를 호출합니다.

다음 예시 각 입력 Movie 문서 의 Genres 필드 반복하는 파이프라인 단계를 만듭니다. Genres 필드 의 각 값에 대해 스테이지에서는 새 Movie 문서 만들고 해당 Genres 필드 입력 문서 의 Genres 값으로 채웁니다.

var pipeline = new EmptyPipelineDefinition<Movie>()
.Unwind(m => m.Genres);

AggregateUnwindOptions 객체 사용하여 Unwind() 메서드의 동작을 사용자 지정할 수 있습니다. 다음 예시 이전 예시 와 동일한 작업을 수행하지만 다음 옵션도 포함되어 있습니다.

  • PreserveNullAndEmptyArrays Genres 필드 에 빈 배열 포함된 문서가 출력에 포함되도록 합니다.

  • IncludeArrayIndex 옵션은 각 출력 문서 에 Index 라는 새 필드 추가합니다. 이 필드 의 값은 입력 문서의 Genres 배열 에 있는 Genres 필드 값의 배열 인덱스 입니다.

var pipeline = new EmptyPipelineDefinition<Movie>()
.Unwind(m => m.Genres,
new AggregateUnwindOptions<Movie>()
{
PreserveNullAndEmptyArrays = true,
IncludeArrayIndex = new ExpressionFieldDefinition<Movie, int>(
m => m.Index)
});

돌아가기

$unset

이 페이지의 내용