$unwind (aggregation)

On this page本页内容

Definition定义

$unwind

Deconstructs 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.每个输出文档都是输入文档,数组字段的值由元素替换。

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. 您可以将数组字段路径传递给$unwindWhen 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带选项的文档操作数

New in version 3.2.版本3.2中的新功能。

You can pass a document to $unwind to specify various behavior options.您可以向$unwind传递文档以指定各种行为选项。

{
  $unwind:
    {
      path: <field path>,
      includeArrayIndex: <string>,
      preserveNullAndEmptyArrays: <boolean>
    }
}
Field字段Type类型Description描述
path string

Field path to an array field. 数组字段的字段路径。To specify a field path, prefix the field name with a dollar sign $ and enclose in quotes.要指定字段路径,请在字段名称前面加上美元符号$并用引号括起来。

includeArrayIndex string

Optional. 可选。The name of a new field to hold the array index of the element. 用于保存元素数组索引的新字段的名称。The name cannot start with a dollar sign $.名称不能以美元符号$开头。

preserveNullAndEmptyArrays boolean

Optional.可选择的

  • If true, if the path is null, missing, or an empty array, $unwind outputs the document.如果为true,则如果pathnull、缺少或为空数组,$unwind将输出文档。
  • If false, if path is null, missing, or an empty array, $unwind does not output a document.如果为false,如果pathnull、缺少或为空数组,$unwind不会输出文档。

The default value is false.默认值为false

Behaviors行为

Non-Array Field Path非数组字段路径

Changed in version 3.2.在版本3.2中更改。$unwind stage no longer errors on non-array operands. $unwind阶段在非数组操作数上不再出现错误。If 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将操作数视为单元素数组。If the operand is null, missing, or an empty array, the behavior of $unwind depends on the value of the preserveNullAndEmptyArrays option.如果操作数为null、缺少或为空数组,$unwind的行为取决于PreserveNullAndEmptyArray选项的值。

Previously, if a value in the field specified by the field path is not an array, db.collection.aggregate() generates an error.以前,如果字段路径指定的字段中的值不是数组,db.collection.aggregate()将生成错误。

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将忽略该输入文档,并且不会输出该输入文档的文档。

New in version 3.2:To output documents where the array field is missing, null or an empty array, use the preserveNullAndEmptyArrays option.若要输出缺少数组字段、空数组或空数组的文档,请使用PreserveNullAndEmptyArray选项。

Examples示例

Unwind Array展开数组

From the mongo shell, create a sample collection named inventory with the following document:mongo shell中,使用以下文档创建名为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数组中的值。

includeArrayIndex and preserveNullAndEmptyArrays

New in version 3.2.版本3.2中的新功能。

From the mongo shell, create a sample collection named inventory2 with the following documents:mongo shell创建名为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 $unwind operations are equivalent and return a document for each element in the sizes field. 以下$unwind操作是等效的,并为sizes字段中的每个元素返回一个文档。If the sizes field does not resolve to an array but is not missing, null, or an empty array, $unwind treats the non-array operand as a single element array.如果sizes字段未解析为数组,但未丢失、为null或为空数组,$unwind将非数组操作数视为单元素数组。

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

The operation returns the following documents:该操作将返回以下文档:

{ "_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

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 of the array index in the new arrayIndex field. 该操作展开sizes数组,并将数组索引的数组索引包含在新增的arrayIndex字段中。If the sizes field does not resolve to an array but is not missing, null, or an empty array, the arrayIndex field is null.如果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

The following $unwind operation uses the preserveNullAndEmptyArrays option to include documents whose sizes field is null, missing, or an empty array.下面的$unwind操作使用preserveNullAndEmptyArrays选项包括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" : 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 by Unwound Values按展开后的值分组

From the mongo shell, create a sample collection named inventory2 with the following documents:mongo shell创建名为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:以下管道展开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 $unwind stage outputs a new document for each element in the sizes array. $unwind阶段为sizes数组中的每个元素输出一个新文档。The stage uses the preserveNullAndEmptyArrays option to include in the output those documents where sizes field is missing, null or an empty array. 该阶段使用preserveNullAndEmptyArrays选项在输出中包括缺少sizes字段、null或空数组的文档。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 by sizes and calculates the average price of each size. $group阶段按sizes对文档进行分组,并计算每个大小的平均价格。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 by averagePrice in descending order. $sort阶段按averagePrice降序对文档进行排序。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") }

See also参阅

Unwind Embedded Arrays展开嵌入式数组

From the mongo shell, create a sample collection named sales with the following documents:mongo shell中,创建一个名为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("1.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 the items 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 the items.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") }

See also参阅

Additional Resources其它资源