展开数组
为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 }
])
下列情况下,$unwind
把sizes
字段看做一个文档:
- 字段存在
- 字段的值不为空
- 字段的值不是空数组
使用$unwind
展开sizes
数组:
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )
操作返回:
{ _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
是一个有元素的数组,$unwind
为sizes
字段的每个元素生成了一个文档 - 在
_id: 3
的文档中,sizes
被解析为只有一个元素的数组 -
_id: 2
、_id: 4
和_id: 5
文档则没有返回,因为sizes
字段不能被解析为单元素数组。
注意:{path: <FIELD>}
是可选的,下面的两个$unwind
操作是等价的:
db.clothing.aggregate( [ { $unwind: "$sizes" } ] )
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )
preserveNullAndEmptyArrays 和 includeArrayIndex
创建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 }
])
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 }
includeArrayIndex
下面的$unwind
操作使用includeArrayIndex
选项,在输出文档中添加了数组元素索引字段。
db.inventory2.aggregate( [
{
$unwind:
{
path: "$sizes",
includeArrayIndex: "arrayIndex"
}
}])
操作展开了sizes
数组,并为输出文档增加了一个数组元素索引字段arrayIndex
,如果sizes
字段不能被解析为一个有元素的数组,但又不是缺失、为空或空数组,则arrayIndex
字段为空。
{ "_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 }
对展开的数组做分组汇总
创建并填充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
数组,并对展开文档的size
字段进行分组:
db.inventory2.aggregate( [
//阶段1
{
$unwind: { path: "$sizes", preserveNullAndEmptyArrays: true }
},
//阶段2
{
$group:
{
_id: "$sizes",
averagePrice: { $avg: "$price" }
}
},
//阶段3
{
$sort: { "averagePrice": -1 }
}
] )
阶段1
$unwind
阶段为sizes
数组的每个元素输出一个文档,该阶段使用preserveNullAndEmptyArrays
选项为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" : 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 }
阶段2
$group
阶段根据sizes
进行分组,并计算所有尺寸价格的平均值。该阶段完成后,生成下面的文档进入下一阶段:
{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }
阶段3
$sort
阶段根据averagePrice
字段值从大到小对文档进行排序,该阶段完成后返回下面的文档:
{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }