Definition定义
$unwindDeconstructs an array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element.从输入文档中解构数组字段,为每个元素输出一个文档。每个输出文档都是输入文档,数组字段的值被元素替换。
Compatibility兼容性
You can use 您可以将$unwind for deployments hosted in the following environments:$unwind用于在以下环境中托管的部署:
- MongoDB Atlas
: The fully managed service for MongoDB deployments in the cloud:云中MongoDB部署的完全托管服务
- MongoDB Enterprise
: The subscription-based, self-managed version of MongoDB:MongoDB的基于订阅的自我管理版本 - MongoDB Community
: The source-available, free-to-use, and self-managed version of MongoDB:MongoDB的源代码可用、免费使用和自我管理版本
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. When using this syntax, $unwind does not output a document if the field value is null, missing, or an empty array.$unwind。使用此语法时,如果字段值为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 |
| |
includeArrayIndex |
| |
preserveNullAndEmptyArrays |
|
Behaviors行为
Non-Array Field Path非数组字段路径
When the operand does not resolve to an array, but is not missing,当操作数未解析为数组,但未丢失、为null, or an empty array,$unwindtreats the operand as a single element array.null或为空数组时,$unwind将操作数视为单个元素数组。When the operand is当操作数为null, missing, or an empty array$unwindfollows 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或空数组的文档,请使用preserveFullAndEmptyArrays选项。
Examples示例
MongoDB Shell
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:$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' }
In document在文档"_id": 1,sizesis a populated array.$unwindreturns a document for each element in thesizesfield."_id": 1中,sizes是一个填充数组。$unwind为sizes字段中的每个元素返回一个文档。In document在文档"_id": 3,sizesresolves to a single element array."_id": 3中,sizes解析为单个元素数组。Documents文档"_id": 2, "_id": 4, and"_id": 5do not return anything because thesizesfield cannot be reduced to a single element array."_id": 2, "_id": 4和"_id": 5不返回任何内容,因为sizes字段不能缩减为单个元素数组。
Note
The { path: <FIELD> } syntax is optional. The following $unwind operations are equivalent.{ path: <FIELD> }语法是可选的。以下$unwind操作是等效的。
db.clothing.aggregate( [ { $unwind: "$sizes" } ] )
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )preserveNullAndEmptyArrays and 和includeArrayIndex
The preserveNullAndEmptyArrays and includeArrayIndex examples use the following collection:preserveFullAndEmptyArrays和includeArrayIndex示例使用以下集合:
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 }
])
preserveNullAndEmptyArrays
The following 以下$unwind operation uses the preserveNullAndEmptyArrays option to include documents whose sizes field is null, missing, or an empty array.$unwind操作使用preserveFullAndEmptyArrays选项来包含其sizes字段为null、缺失或为空数组的文档。
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: 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 }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. 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.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 }Group by Unwound Values按未受伤害的价值观分组
In 在mongosh, create a sample collection named inventory2 with the following documents:mongosh中,使用以下文档创建一个名为investory2的示例集合:
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 }
])
The following pipeline unwinds the 以下管道将展开sizes array and groups the resulting documents by the unwound size values:sizes数组,并根据展开的大小值对生成的文档进行分组:
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$unwindstage outputs a new document for each element in thesizesarray.$unwind阶段为sizes数组中的每个元素输出一个新文档。The stage uses the preserveNullAndEmptyArrays option to include in the output those documents where该阶段使用sizesfield is missing, null or an empty array. This stage passes the following documents to the next stage:preserveFullAndEmptyArrays选项在输出中包含那些缺少sizes字段、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 }Second Stage:第二阶段:The$groupstage groups the documents bysizesand calculates the average price of each size. This stage passes the following documents to the next stage:$group阶段按大小对文档进行分组,并计算每种大小的平均价格。此阶段将以下文件传递到下一阶段:{ _id: "S", averagePrice: Decimal128("80") }
{ _id: "L", averagePrice: Decimal128("80") }
{ _id: "M", averagePrice: Decimal128("120") }
{ _id: null, averagePrice: Decimal128("45.25") }Third Stage:第三阶段:The$sortstage sorts the documents byaveragePricein descending order. The operation returns the following result:$sort阶段按averagePrice降序对文档进行排序。该操作返回以下结果:{ _id : "M", averagePrice: Decimal128("120") }
{ _id : "L", averagePrice: Decimal128("80") }
{ _id : "S", averagePrice: Decimal128("80") }
{ _id : null, averagePrice: Decimal128("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: 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")
}
]
}
])
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第一个$unwindstage outputs a new document for each element in theitemsarray:$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 } }Second Stage第二阶段The second第二个$unwindstage outputs a new document for each element in theitems.tagsarrays:$unwill阶段为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 } }Third Stage第三阶段The$groupstage groups the documents by the tag and calculates the total sales amount of items with each tag:$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#
The C# examples on this page use the 本页上的C#示例使用Atlas示例数据集中的sample_mflix database from the Atlas sample datasets. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB .NET/C# Driver documentation.sample_mflix数据库。要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅MongoDB .NET/C#驱动程序文档中的入门。
The following 以下Movie class models the documents in the sample_mflix.movies collection: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; }
[]
public DateTime LastUpdated { get; set; }
}
Note
ConventionPack for Pascal CasePascal大小写的约定包
The C# classes on this page use Pascal case for their property names, but the field names in the MongoDB collection use camel case. To account for this difference, you can use the following code to register a 此页面上的C#类使用Pascal大小写作为其属性名,但MongoDB集合中的字段名使用驼峰大小写。为了解释这种差异,您可以在应用程序启动时使用以下代码注册ConventionPack when your application starts:ConventionPack:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);To use the MongoDB .NET/C# driver to add a 要使用MongoDB .NET/C#驱动程序向聚合管道添加$unwind stage to an aggregation pipeline, call the Unwind() method on a PipelineDefinition object.$unwind阶段,请在PipelineDefinition对象上调用Unwind()方法。
The following example creates a pipeline stage that iterates over the 以下示例创建了一个管道阶段,该阶段迭代每个输入Genres field in each input Movie document. Movie文档中的Genres字段。For each value in the 对于Genres field, the stage creates a new Movie document and populates its Genres field with the Genres value from the input document.Genres字段中的每个值,阶段都会创建一个新的Movie文档,并用输入文档中的Genres值填充其Genres字段。
var pipeline = new EmptyPipelineDefinition<Movie>()
.Unwind(m => m.Genres);
You can use an AggregateUnwindOptions object to customize the behavior of the 您可以使用Unwind() method. AggregateUnwindOptions对象自定义Unwind()方法的行为。The following example performs the same operation as the previous example, but also includes the following options:以下示例执行与前一个示例相同的操作,但还包括以下选项:
PreserveNullAndEmptyArraysensures that documents that contain an empty array in the确保输出中包含Genresfield are included in the output.Genres字段中包含空数组的文档。TheIncludeArrayIndexoption adds a new field namedIndexto each output document. The value of this field is the array index of theGenresfield's value in the input document'sGenresarray.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)
});Node.js
The Node.js examples on this page use the 本页上的Node.js示例使用Atlas示例数据集中的sample_mflix database from the Atlas sample datasets. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB Node.js driver documentation.sample_mflix数据库。要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门。
To use the MongoDB Node.js driver to add a 要使用MongoDB Node.js驱动程序向聚合管道中添加$unwind stage to an aggregation pipeline, use the $unwind operator in a pipeline object.$unwind阶段,请在管道对象中使用$unwind运算符。
The following example creates a pipeline stage that iterates over the 以下示例创建了一个管道阶段,该阶段迭代每个输入genres field in each input movie document. movie文档中的genres字段。For each value in the 对于genres field, the stage creates a new movie document and populates its genres field with the genres value from the input document. genres字段中的每个值,阶段都会创建一个新的movie文档,并用输入文档中的流派值填充其流派字段。The example then runs the aggregation pipeline:然后,该示例运行聚合管道:
const pipeline = [{ $unwind: "$genres" }];
const cursor = collection.aggregate(pipeline);
return cursor;
You can customize the behavior of the 您可以自定义$unwind method. The following example performs the same operation as the previous example, but also includes the following options:$unwill方法的行为。以下示例执行与前一个示例相同的操作,但还包括以下选项:
preserveNullAndEmptyArraysensures that documents that contain an empty array in the确保在genresfield are included in the output.genres字段中包含空数组的文档包含在输出中。includeArrayIndexadds a new field named为每个输出文档添加一个名为indexto each output document. The field contains the array index of thegenresvalue in the input document'sgenresfield.index的新字段。该字段包含输入文档流派字段中genres值的数组索引。
const pipeline = [
{
$unwind: {
path: "$genres",
preserveNullAndEmptyArrays: true,
includeArrayIndex: "index"
}
}
];
const cursor = collection.aggregate(pipeline);
return cursor;Learn More了解更多
To learn more about related methods, see the 要了解有关相关方法的更多信息,请参阅$group, $sum, and $multiply guides.$group、$sum和$multiply指南。
To see how to use 要查看如何在完整示例中使用$unwind in a full example, see the Unwind Arrays and Group Data tutorial.$unwind,请参阅展开数组和组数据教程。