mongodb聚合(mongodb聚合操作)
本篇文章给大家谈谈mongodb聚合,以及mongodb聚合操作对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、mongodb Aggregation聚合操作之$unwind
- 2、MongoDB 轻松搞定统计 —— 聚合函数使用
- 3、mongoDB表与表的关系及聚合管道查询
- 4、mongodb Aggregation聚合操作之$bucket
- 5、mongodb Aggregation聚合操作之$sort
mongodb Aggregation聚合操作之$unwind
在上一篇 mongodb Aggregation聚合操作之$project 中详细介绍了mongodb聚合操作中的$project使用以及参数细节。本篇将开始介绍Aggregation聚合操作中的unwind操作。
说明:
解析输入文档中的数组字段指历大,为每个元素输出一个文档。每个输出文档都是输入文档,数组字段的值被元素替换。如果字段值为null、缺失或数组为空,则$unwind不会输出文档。
语法:
{ $unwind: field path }
可以将文档传递给$unwind以指定各种行为选项。
{
$unwind:
{
path: field path,
includeArrayIndex: string,
preserveNullAndEmptyArrays: boolean
}
}
参数解析:
path:string类型,数组字段的字段路径。若要指定字段路径,请在字段名称前加上美元符号$并将其括在引号中。
includeArrayIndex:string类型,可选的。用于保存元素的数组索引的新字段的名称。新字段名称不能以美元符号$开头。
preserveNullAndEmptyArrays:boolean类型,可选的。如果为真,如果路径为空、丢失或数组为空,则$unwind输出文档。如果为false,如果路径为空、丢失或数组为空,则$unwind不输出文档。默认值为false。
初始化数据:
db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
示例:按照sizes字段拆分数据
db.inventory.aggregate( [ { $unwind : "$sizes" } ] )
结果:
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }
初始化数据:
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 }
])
示例:
下烂指面的$unwind操作是等效的,并为size字段中的每个元素返回一个文档。如果size字段没唯竖有解析为数组,但没有丢失、null或空数组,则$unwind将非数组操作数视为单个元素数组。
db.inventory2.aggregate( [ { $unwind: "$sizes" } ] )
db.inventory2.aggregate( [ { $unwind: { path: "$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" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }
示例:下面的$unwind操作使用includeArrayIndex选项在输出中包含数组索引。
db.inventory2.aggregate( [
{
$unwind:
{
path: "$sizes",
includeArrayIndex : "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 }
示例:下面的$unwind操作使用preserveNullAndEmptyArrays选项来包含size字段为null、缺失或空数组的文档。
db.inventory2.aggregate( [
{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }
] )
{ "_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 }
初始化数据:
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 }
])
示例:下面的管道将展开大小数组,并将产生的文档按展开后的大小值进行分组:
db.inventory2.aggregate( [
// First Stage
{
$unwind: { path: "$sizes", preserveNullAndEmptyArrays: true }
},
// Second Stage
{
$group:
{
_id: "$sizes",
averagePrice: { $avg: "$price" }
}
},
// Third Stage
{
$sort: { "averagePrice": -1 }
}
] )
结果:
{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }
初始化数据:
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")
}
]
}
])
示例:下面的操作将按标签销售的商品分组,并计算每个标签的总销售额。
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" ] }
}
}
}
])
结果:
{ "_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") }
MongoDB 轻松搞定统计 —— 聚合函数使用
在 MySQL 中我们通常使用 SELECT count(*) FROM table_name WHERE ... 来获取满足某个条件的记录条数。在 MondoDB 中还提供了类似的方法。MongoDB 有如下方式:
以下面的数据为例:
查找男性的用户数量可以这样做:
如果要实现条件查询呢,使用条件即可,比如查询性别为男,年龄大于等于15的用户:
条件的时候和之前条件查询的用法一样,可以参考: MongoDB 条件查询和排序 。
MongoDB 同样提供了分组计数的方法。比如要统计男女性别的人数,可以按如下方式进行:
求和通过聚合的$sum 操作符来完成,可以笑段用来计算某一个数值列的和,例如我们要计算所有年龄之和。
这里_id 指定为 null 是就是对全部数据进行求和(即不散脊分组),若指定了列,则可以分组求和,比如对男性和女性分别求和。
求和也可以对多个字段进行求和,以下面的外卖订单冲升渗数据为例:
我们想知道算上配送费的订单总额,可以像下面那样做,如果我们加上商品名称也可以得到每个商品的销售总额。
平均值通过$avg 操作符完成,例如上面数据的计算平均客单价:
本篇介绍了 MongoDB 的聚合函数的基本用法,包括计数、求和和取平均值。通过 MongoDB 提供了聚合函数可以高效地完成统计工作。
[img]mongoDB表与表的关系及聚合管道查询
MongoDB 中的关系可以是:
MongoDB 聚合管道(Aggregation Pipeline)
使用聚合管道可以对集合中的文档进行变换和组合。
管道操作符
$project 修改文档的结构,可以用来重命名、增加或删除文档中的谈羡字段。
$match 用于过滤文档。用法类似于 find() 方法中的参数。
$limit 用来限制MongoDB聚合管道返回的文档数
$skip 在聚合管羡侍祥道中跳过指定数量的文档,并返回余下的文档。兄搏
$sort 将输入文档排序后输出
$group 将集合中的文档进行分组,可用于统计结果
$lookup 可以引用其他集合的数据(表关联查询)
创建数据
mongodb Aggregation聚合操作之$bucket
在上一篇 mongodb Aggregation聚合操作之$facet 中详细介绍了mongodb聚合操作中的$facet使用以及参数细节。本篇将开始介绍Aggregation聚合操作中的$bucket操作。
说明:
根据指定的表达式和bucket边界将传入的文档分类到称为bucket的组中,并为每个bucket输出一个文档。每个输出文档都包含一个_id字段,其值指定bucket的包含下界。输出选项指定每个输出文档中包含的字段。
$bucket只为至少包含一个腔咐输入文档的bucket生成输出文档。
语法:
{
$bucket: {
groupBy: expression,
boundaries: [ lowerbound1, lowerbound2, ... ],
default: literal,
output: {
output1: { $accumulator expression },
...
outputN: { $accumulator expression }
}
}
}
参数讲解:
groupBy:用来对文档进行分组的表达式。要指定字段路径,请在字段名称前加上美元符号$并将其括在引号中。除非$bucket包含默兄圆咐认规范,否则每个输入文档必须将groupBy字段路径或表达式解析为属于边界指定的范围之一的值。
boundaries:一个基于groupBy表达式的值数组,该表达式指定每个bucket的边界。每一对相邻的值充当桶的包含下边界和独占上边界。您必须指定至少两个边界。
default:可选的。指定附加bucket的_id的文字,该bucket包含groupBy表达式结果不属于边界指定的bucket的所有文档。如果未指定,则每个输入文档必须将groupBy表达式解析为由边界指定的bucket范围中的一个值,否则操作将抛出错误。默认值必须小于最低边界值,或大于或等于最高边界值。
默认值可以是与边界项不同的类型。
output:可选的。除_id字段外,指定输出文档中要包含的字段的文档。要指定要包含的字段,必须使用累加器表达式。
初始化数据:
db.artists.insertMany([
{ "_id" : 1, "last_name" : "Bernard", "first_name" : "Emil"羡纯, "year_born" : 1868, "year_died" : 1941, "nationality" : "France" },
{ "_id" : 2, "last_name" : "Rippl-Ronai", "first_name" : "Joszef", "year_born" : 1861, "year_died" : 1927, "nationality" : "Hungary" },
{ "_id" : 3, "last_name" : "Ostroumova", "first_name" : "Anna", "year_born" : 1871, "year_died" : 1955, "nationality" : "Russia" },
{ "_id" : 4, "last_name" : "Van Gogh", "first_name" : "Vincent", "year_born" : 1853, "year_died" : 1890, "nationality" : "Holland" },
{ "_id" : 5, "last_name" : "Maurer", "first_name" : "Alfred", "year_born" : 1868, "year_died" : 1932, "nationality" : "USA" },
{ "_id" : 6, "last_name" : "Munch", "first_name" : "Edvard", "year_born" : 1863, "year_died" : 1944, "nationality" : "Norway" },
{ "_id" : 7, "last_name" : "Redon", "first_name" : "Odilon", "year_born" : 1840, "year_died" : 1916, "nationality" : "France" },
{ "_id" : 8, "last_name" : "Diriks", "first_name" : "Edvard", "year_born" : 1855, "year_died" : 1930, "nationality" : "Norway" }
])
示例:
db.artists.aggregate( [
// First Stage
{
$bucket: {
groupBy: "$year_born", // 按year_born字段分组
boundaries: [ 1840, 1850, 1860, 1870, 1880 ], // 桶的边界
default: "Other", // 不属于Bucket的文档的Bucket id【如果一个文档不包含year_born字段,或者它的year_born字段在上面的范围之外,那么它将被放在_id值为“Other”的默认bucket中。】
output: { //输出
"count": { $sum: 1 },
"artists" :
{
$push: {
"name": { $concat: [ "$first_name", " ", "$last_name"] },
"year_born": "$year_born"
}
}
}
}
},
// 筛选结果大于3的
{
$match: { count: {$gt: 3} }
}
] )
结果是:
{
"_id" : 1860.0, //桶的包含下界。
"count" : 4.0,//桶中文档的计数。
"artists" : [ //包含bucket中每个艺术家信息的文档数组。每个文档都包含了艺术家的name,它是艺术家的first_name和last_name的连接(即$concat)
{
"name" : "Emil Bernard",
"year_born" : 1868.0
},
{
"name" : "Joszef Rippl-Ronai",
"year_born" : 1861.0
},
{
"name" : "Alfred Maurer",
"year_born" : 1868.0
},
{
"name" : "Edvard Munch",
"year_born" : 1863.0
}
]
}
可以使用$facet阶段在单个阶段中执行多个$bucket聚合。
初始化数据:
db.artwork.insertMany([
{ "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926,
"price" : NumberDecimal("199.99") },
{ "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902,
"price" : NumberDecimal("280.00") },
{ "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925,
"price" : NumberDecimal("76.04") },
{ "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai",
"price" : NumberDecimal("167.30") },
{ "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,
"price" : NumberDecimal("483.00") },
{ "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,
"price" : NumberDecimal("385.00") },
{ "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893
/* No price*/ },
{ "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918,
"price" : NumberDecimal("118.42") }
])
示例:下面的操作使用$facet阶段中的两个$bucket阶段创建两个分组,一个按价格,另一个按年:
db.artwork.aggregate( [
{
$facet: { // 顶级$facet stage
"price": [ // Output field 1
{
$bucket: {
groupBy: "$price", // Field to group by
boundaries: [ 0, 200, 400 ], // Boundaries for the buckets
default: "Other", // Bucket id for documents which do not fall into a bucket
output: { // Output for each bucket
"count": { $sum: 1 },
"artwork" : { $push: { "title": "$title", "price": "$price" } },
"averagePrice": { $avg: "$price" }
}
}
}
],
"year": [ // Output field 2
{
$bucket: {
groupBy: "$year", // Field to group by
boundaries: [ 1890, 1910, 1920, 1940 ], // Boundaries for the buckets
default: "Unknown", // Bucket id for documents which do not fall into a bucket
output: { // Output for each bucket
"count": { $sum: 1 },
"artwork": { $push: { "title": "$title", "year": "$year" } }
}
}
}
]
}
}
] )
结果:
[ { price:
[ { _id: 0,
count: 4,
artwork:
[ { title: 'The Pillars of Society',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer 1f 4e 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } },
{ title: 'Dancer',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer b4 1d 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } },
{ title: 'The Great Wave off Kanagawa',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer 5a 41 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } },
{ title: 'Blue Flower',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer 42 2e 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } } ],
averagePrice:
{ _bsontype: 'Decimal128',
bytes: Buffer d7 6d 15 00 00 00 00 00 00 00 00 00 00 00 38 30 } },
{ _id: 200,
count: 2,
artwork:
[ { title: 'Melancholy III',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer 60 6d 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } },
{ title: 'Composition VII',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer 64 96 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } } ],
averagePrice:
{ _bsontype: 'Decimal128',
bytes: Buffer e2 81 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } },
{ _id: 'Other',
count: 2,
artwork:
[ { title: 'The Persistence of Memory',
price:
{ _bsontype: 'Decimal128',
bytes: Buffer ac bc 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } },
{ title: 'The Scream' } ],
averagePrice:
{ _bsontype: 'Decimal128',
bytes: Buffer ac bc 00 00 00 00 00 00 00 00 00 00 00 00 3c 30 } } ],
year:
[ { _id: 1890,
count: 2,
artwork:
[ { title: 'Melancholy III', year: 1902 },
{ title: 'The Scream', year: 1893 } ] },
{ _id: 1910,
count: 2,
artwork:
[ { title: 'Composition VII', year: 1913 },
{ title: 'Blue Flower', year: 1918 } ] },
{ _id: 1920,
count: 3,
artwork:
[ { title: 'The Pillars of Society', year: 1926 },
{ title: 'Dancer', year: 1925 },
{ title: 'The Persistence of Memory', year: 1931 } ] },
{ _id: 'Unknown',
count: 1,
artwork: [ { title: 'The Great Wave off Kanagawa' } ] } ] } ]
mongodb Aggregation聚合操作之$sort
在上一篇 mongodb Aggregation聚合操作之$match 中详细介绍了mongodb聚合操作中的$match使用以及参数细节。本篇将开始介绍Aggregation聚合操作中的$sort操作。
说明:
对所有输入文档进行排序,并将它们按排序顺序返回到管道。
语法:
{ $sort: { field1: sort order, field2: sort order ... } }
$sort接收一个文档,该文档指定要排序的字段和相应的排序顺序。排序顺序可以有以下值之一:
1:升序排序
-1:降序排序
{ $meta: "textScore" }:按计算的textScore元数据降序排序。
注意【如果对多个字段进行排序,则从左者弯搏到右计算排序顺序。例如,在上面的表单中,文档首先按field1排序。然后,具有相同field1值的文档按field2进一步排序。】示例
对于要排序的字段或字段,将排序顺序设置为1或-1,分别指定升序或降序排序,如下例所示:该操作对users集合中的文档进行排序,根据age字段降序排列,然后根据posts字段中的值升序排列。
db.users.aggregate(
[
{ $sort : { age : -1, posts: 1 } }
]
)
在{sort-key}文档中指定计算出的元数据的新字段名,并指定$meta表达式作为它的值,如下面的示例所示:该操作使用$text操作符匹配文档,然后首先按“textScore”元数据排序,然后按posts字段的降序排序。指定的元数据决定排序顺序。例如,“textScore”元数据按降序排序。
db.users.aggregate(
[
{ $match: { $text: { $search: "operating" } } },
首祥 { $sort: { score: { $meta: "textScore" }, posts: -1 } }
]
)
$sort + $limit内存优化
当$sort在$limit之前并且没有修改文档数量的中间阶段时,优化器可以将$limit合并到$sort中。这允许$sort操作在进行过程中只维护顶部的n个结果,其中n是指定的限制,并确保MongoDB只需要在内存中存储n个项目。当allowDiskUse为true且n项超过聚合内存限制时,这种优化仍然适用。优化可能会在不同版本之间发生变化。
$sort阶段的RAM有100兆字节的限制。默认情况下,如果阶段超过这个限制,$sort将产生一个错误。为了允许处理大型数据集,将allowDiskUse选项设置为true,以允许$sort操作写入临时文件。有关详细信息,请参阅db.collection.aggregate()方法中的allowDiskUse选项和aggregate命令。
版本2.6中的变化:$sort的内存限制从RAM的10%更改为100兆字节。
如果将$sort操作符放置在管道的开闹谈头,或放置在$project、$unwind和$group聚合操作符之前,则可以利用索引。如果$project、$unwind或$group发生在$sort操作之前,则$sort不能使用任何索引
关于mongodb聚合和mongodb聚合操作的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。