$unwind (aggregation)
On this page本页内容
Definition定义
Syntax语法
You can pass a field path operand or a document operand to unwind an array field.可以传递字段路径操作数或文档操作数来展开数组字段。
Field Path Operand字段路径操作数
You can pass the array field path to 您可以将数组字段路径传递到$unwind
. $unwind
。When using this syntax, 使用此语法时,如果字段值为$unwind
does not output a document if the field value is null, missing, or an empty array.null
、缺少或为空数组,$unwind
不会输出文档。
{ $unwind: <field path> }
When you specify the field path, prefix the field name with a dollar sign 指定字段路径时,请在字段名称前面加上美元符号$
and enclose in quotes.$
并用引号括起来。
Document Operand with Options带选项的文档操作数
You can pass a document to 您可以将文档传递给$unwind
to specify various behavior options.$unwind
以指定各种行为选项。
{
$unwind:
{
path: <field path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}
path | string | $ and enclose in quotes. $ 并用引号括起来。 |
includeArrayIndex | string | $ . $ 开头。 |
preserveNullAndEmptyArrays | boolean |
false . false 。 |
Behaviors行为
Non-Array Field Path非数组字段路径
When the operand does not resolve to an array, but is not missing,当操作数未解析为数组,但不缺少、为null
, or an empty array,$unwind
treats the operand as a single element array.null
或为空数组时,$unwind
将操作数视为单个元素数组。When the operand is当操作数为null
, missing, or an empty array$unwind
follows the behavior set for the preserveNullAndEmptyArrays option.null
、缺少或为空数组时,$unwind
将遵循为preserveNullAndEmptyArrays
选项设置的行为。
Missing Field缺少字段
If you specify a path for a field that does not exist in an input document or the field is an empty array, 如果为输入文档中不存在的字段指定了路径,或者该字段是空数组,则默认情况下$unwind
, by default, ignores the input document and will not output documents for that input document.$unwind
将忽略输入文档,并且不会输出该输入文档的文档。
To output documents where the array field is missing, null or an empty array, use the preserveNullAndEmptyArrays option.若要输出缺少数组字段、null
或空数组的文档,请使用preserveNullAndEmptyArrays
选项。
Examples实例
Unwind Array展开数组
In 在mongosh
, create a sample collection named inventory
with the following document:mongosh
中,使用以下文档创建一个名为inventory
的样本集合:
db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
The following aggregation uses the 以下聚合使用$unwind
stage to output a document for each element in the sizes
array:$unwind
阶段为sizes
数组中的每个元素输出一个文档:
db.inventory.aggregate( [ { $unwind : "$sizes" } ] )
The operation returns the following results:该操作返回以下结果:
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }
Each document is identical to the input document except for the value of the 除了sizes
field which now holds a value from the original sizes
array.sizes
字段的值之外,每个文档都与输入文档相同,该字段现在保存原始sizes
数组中的值。
Missing or Non-array Values缺少值或非数组值
Consider the 考虑一下clothing
collection: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
treats the sizes
field as a single element array if:$unwind
将size
字段视为单个元素数组:
the field is present,存在场,the value is not null, and该值不为null
,并且the value is not an empty array.该值不是空数组。
Expand the 使用sizes
arrays with $unwind
:$unwind
扩展sizes
数组:
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )
The $unwind
operation returns:
{ _id: 1, item: 'Shirt', sizes: 'S' },
{ _id: 1, item: 'Shirt', sizes: 'M' },
{ _id: 1, item: 'Shirt', sizes: 'L' },
{ _id: 3, item: 'Hat', sizes: 'M' }
In document在文档"_id": 1
,sizes
is a populated array.$unwind
returns a document for each element in thesizes
field."_id": 1
中,sizes
是一个填充的数组。$unwind
为sizes
字段中的每个元素返回一个文档。In document在文档"_id": 3
,sizes
resolves to a single element array."_id": 3
中,size
解析为单个元素数组。Documents文档"_id": 2, "_id": 4
, and"_id": 5
do not return anything because thesizes
field cannot be reduced to a single element array."_id": 2, "_id": 4
和"_id": 5
不返回任何内容,因为sizes
字段不能缩减为单个元素数组。
preserveNullAndEmptyArrays
and 和includeArrayIndex
The preserveNullAndEmptyArrays
and includeArrayIndex
examples use the following collection: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
The following $unwind
operation uses the preserveNullAndEmptyArrays option to include documents whose sizes
field is null, missing, or an empty array.
db.inventory2.aggregate( [
{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }
] )
The output includes those documents where the 输出包括sizes
field is null, missing, or an empty array: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
The following 以下$unwind
operation uses the includeArrayIndex option to include the array index in the output.$unwind
操作使用includeArrayIndex
选项将数组索引包括在输出中。
db.inventory2.aggregate( [
{
$unwind:
{
path: "$sizes",
includeArrayIndex: "arrayIndex"
}
}])
The operation unwinds the 该操作将展开sizes
array and includes the array index in the new arrayIndex
field. sizes
数组,并将数组索引包含在新的arrayIndex
字段中。If the sizes
field does not resolve to a populated array but is not missing, null, or an empty array, the arrayIndex
field is 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 }
Group by Unwound Values按展开值分组
In 在mongosh
, create a sample collection named inventory2
with the following documents: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 }
])
The following pipeline unwinds the sizes
array and groups the resulting documents by the unwound size values:
db.inventory2.aggregate( [
// First Stage
{
$unwind: { path: "$sizes", preserveNullAndEmptyArrays: true }
},
// Second Stage
{
$group:
{
_id: "$sizes",
averagePrice: { $avg: "$price" }
}
},
// Third Stage
{
$sort: { "averagePrice": -1 }
}
] )
First Stage:第一阶段:-
The
$unwind
stage outputs a new document for each element in thesizes
array. The stage uses the preserveNullAndEmptyArrays option to include in the output those documents wheresizes
field is missing, null or an empty array. This stage passes the following documents to the next stage:{ "_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 } Second Stage:第二阶段:-
The
$group
stage groups the documents bysizes
and calculates the average price of each size. This stage passes the following documents to the next stage:{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") } Third Stage:第三阶段:-
The
$sort
stage sorts the documents byaveragePrice
in descending order. The operation returns the following result:{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }
Unwind Embedded Arrays展开嵌入式数组
In 在mongosh
, create a sample collection named sales
with the following documents: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")
}
]
}
])
The following operation groups the items sold by their tags and calculates the total sales amount per each tag.以下操作按标签对销售的商品进行分组,并计算每个标签的总销售额。
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" ] }
}
}
}
])
First Stage第一阶段-
The first第一个$unwind
stage outputs a new document for each element in theitems
array:$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 } } Second Stage第二阶段-
The second第二个$unwind
stage outputs a new document for each element in theitems.tags
arrays:$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 } } Third Stage第三阶段-
The$group
stage groups the documents by the tag and calculates the total sales amount of items with each tag:$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") }