茂名模板建站哪家好,简单的手机网站模板下载安装,成都网站制作推来客网站系统,浙江质监站网址聚合
聚合操作处理多个文档并返回计算结果。您可以使用聚合操作来#xff1a; 将多个文档中的值分组在一起。 对分组数据执行操作以返回单个结果。 分析数据随时间的变化。
要执行聚合操作#xff0c;您可以使用#xff1a; 聚合管道 单一目的聚合方法 Map-reduce 函…聚合
聚合操作处理多个文档并返回计算结果。您可以使用聚合操作来 将多个文档中的值分组在一起。 对分组数据执行操作以返回单个结果。 分析数据随时间的变化。
要执行聚合操作您可以使用 聚合管道 单一目的聚合方法 Map-reduce 函数
聚合管道
聚合管道由一个或多个处理文档的阶段组成 除$out、$merge、$geoNear和$changeStream阶段之外的所有阶段都可以在管道中出现多次。 每个阶段都对输入文档执行操作。例如阶段可以过滤文档、对文档进行分组以及计算值。 从一个阶段输出的文档将输入到下一阶段。 聚合管道可以返回文档组的结果。例如返回总计、平均值、最大值和最小值。
聚合阶段
在db.collection.aggregate()方法和db.aggregate()方法中管道阶段出现在数组中。文档按顺序经过这些阶段。
db.collection.aggregate( [ { stage }, ... ] )常见几种阶段
阶段描述$group按指定的标识符表达式对输入文档进行分组并在指定的情况下对每个组应用累加器表达式。消耗所有输入文档并为每个不同的组输出一个文档。输出文档只包含标识符字段如果指定的话还包含累积字段。$limit将未修改的前n 个文档传递到管道其中n是指定的限制。对于每个输入文档输出一个文档前n 个文档或零个文档前n 个文档之后。$match过滤文档流以仅允许匹配的文档未经修改地传递到下一个管道阶段。 $match使用标准 MongoDB 查询。对于每个输入文档输出一个文档匹配或零个文档不匹配。$merge将聚合管道的结果文档写入集合。该阶段可以将结果合并插入新文档、合并文档、替换文档、保留现有文档、操作失败、使用自定义更新管道处理文档结果到输出集合中。要使用该$merge阶段它必须是管道中的最后一个阶段。$out将聚合管道的结果文档写入集合。要使用该$out阶段它必须是管道中的最后一个阶段。$project重塑流中的每个文档例如通过添加新字段或删除现有字段。对于每个输入文档输出一个文档。$sort按指定的排序键对文档流重新排序。仅顺序发生变化文件保持不变。对于每个输入文档输出一个文档。$unwind从输入文档解构数组字段以输出每个元素的文档。每个输出文档都用一个元素值替换数组。对于每个输入文档输出n个文档其中n是数组元素的数量对于空数组可以为零。
测试数据如下
sit_rs1:PRIMARY db.orders.find()
{ _id : 4, cust_id : B, ord_date : ISODate(2023-06-18T00:00:00Z), price : 26, items : [ { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 6, cust_id : C, ord_date : ISODate(2023-06-19T00:00:00Z), price : 38, items : [ { sku : carrots, qty : 10, price : 1 }, { sku : apples, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 1, cust_id : A, ord_date : ISODate(2023-06-01T00:00:00Z), price : 15, items : [ { sku : apple, qty : 5, price : 2.5 }, { sku : apples, qty : 5, price : 2.5 } ], status : 1 }
{ _id : 2, cust_id : A, ord_date : ISODate(2023-06-08T00:00:00Z), price : 60, items : [ { sku : apple, qty : 8, price : 2.5 }, { sku : banana, qty : 5, price : 10 } ], status : 1 }
{ _id : 9, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 51, items : [ { sku : carrots, qty : 5, price : 1 }, { sku : apples, qty : 10, price : 2.5 }, { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 3, cust_id : B, ord_date : ISODate(2023-06-08T00:00:00Z), price : 55, items : [ { sku : apple, qty : 10, price : 2.5 }, { sku : pears, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 5, cust_id : B, ord_date : ISODate(2023-06-19T00:00:00Z), price : 40, items : [ { sku : banana, qty : 5, price : 10 } ], status : 1 }
{ _id : 7, cust_id : C, ord_date : ISODate(2023-06-20T00:00:00Z), price : 21, items : [ { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 8, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 76, items : [ { sku : banana, qty : 5, price : 10 }, { sku : apples, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 10, cust_id : D, ord_date : ISODate(2023-06-23T00:00:00Z), price : 23, items : [ { sku : apple, qty : 10, price : 2.5 } ], status : 1 }示例一:
查询客户: “D” 的订单按日期分组返回每天的订单总价
$match 阶段
匹配 “cust_id” : “D” 的记录。将过滤后的文档输出到 group 阶段。
$group 阶段
输入的文档按 ord_date 进行分组。使用 $sum 运算符计算价格总和并将结果存放聚合管道 sumPrice 字段中。
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { cust_id : D } },
... { $group: { _id: $ord_date, sumPrice: { $sum: $price } } }
... ] )
{ _id : ISODate(2023-06-20T00:00:00Z), sumPrice : 127 }
{ _id : ISODate(2023-06-23T00:00:00Z), sumPrice : 23 }示例二
按照客户进行分组统计每个客户的订单总价并总价降序排序。取前三名的客户如下
$group 阶段
输入的文档按 cust_id进行分组。使用 $sum 运算符计算价格总和并将结果存放聚合管道 sumPrice 字段中。
$sort 阶段
按 sumPrice 字段以相反的顺序对这些文档进行排序。
$limit 阶段
运算 $limit 仅包含前 3 个结果文档。
sit_rs1:PRIMARY db.orders.aggregate(
... [
... { $group : { _id : $cust_id , sumPrice : { $sum : $price } } },
... { $sort : { sumPrice : -1 } },
... { $limit : 3 }
... ]
... )
{ _id : D, sumPrice : 150 }
{ _id : B, sumPrice : 121 }
{ _id : A, sumPrice : 75 }示例三
按照客户进行分组统计每个客户的订单总价并输出到结果集合agg_cust_id_1 如下
$group 阶段
输入的文档按 cust_id进行分组。使用 $sum 运算符计算价格总和并将结果存放聚合管道 value字段中。
$out 阶段
将输出写入集合 agg_cust_id_1
sit_rs1:PRIMARY db.orders.aggregate([
... { $group: { _id: $cust_id, value: { $sum: $price } } },
... { $out: agg_cust_id_1 }
... ])# 查询 agg_cust_id_1 集合以验证结果
sit_rs1:PRIMARY db.agg_cust_id_1.find()
{ _id : A, value : 75 }
{ _id : D, value : 150 }
{ _id : B, value : 121 }
{ _id : C, value : 59 }sit_rs1:PRIMARY db.orders.find({}, { cust_id: 1, price: 1})
{ _id : 4, cust_id : B, price : 26 }
{ _id : 6, cust_id : C, price : 38 }
{ _id : 1, cust_id : A, price : 15 }
{ _id : 2, cust_id : A, price : 60 }
{ _id : 9, cust_id : D, price : 51 }
{ _id : 3, cust_id : B, price : 55 }
{ _id : 5, cust_id : B, price : 40 }
{ _id : 7, cust_id : C, price : 21 }
{ _id : 8, cust_id : D, price : 76 }
{ _id : 10, cust_id : D, price : 23 }示例四
计算某个SKU单品总共下了多少单销售总数量及平均每单数量是多少如下
首先查询日期大于等于 2023-03-01 的订单 按数组 items 字段 分解文档即如果数组包含N个元素将分解为N个文档。 再对 items.sku进行分组统计并计算 qty 的数量总和。 orders_ids 把相同组的订单ID号添加到数组。
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { ord_date: { $gte: new Date(2023-03-01) } } },
... { $unwind: $items },
... { $group: { _id: $items.sku, qty: { $sum: $items.qty }, orders_ids: { $addToSet: $_id } } },
... { $project: { value: { count: { $size: $orders_ids }, qty: $qty, avg: { $divide: [ $qty, { $size: $orders_ids } ] } } } },
... { $merge: { into: agg_sku, on: _id, whenMatched: replace, whenNotMatched: insert } }
... ] )# 查询 agg_sku 集合以验证结果
sit_rs1:PRIMARY db.agg_sku.find()
{ _id : apple, value : { count : 7, qty : 63, avg : 9 } }
{ _id : banana, value : { count : 3, qty : 15, avg : 5 } }
{ _id : apples, value : { count : 4, qty : 35, avg : 8.75 } }
{ _id : carrots, value : { count : 2, qty : 15, avg : 7.5 } }
{ _id : pears, value : { count : 1, qty : 10, avg : 10 } }接下来各阶段执行过程详细如下
$match阶段
该阶段仅选择那些大于或等于2023-03-01 的文档输出如下
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { ord_date: { $gte: new Date(2023-03-01) } } }
... ] )
{ _id : 2, cust_id : A, ord_date : ISODate(2023-06-08T00:00:00Z), price : 60, items : [ { sku : apple, qty : 8, price : 2.5 }, { sku : banana, qty : 5, price : 10 } ], status : 1 }
{ _id : 3, cust_id : B, ord_date : ISODate(2023-06-08T00:00:00Z), price : 55, items : [ { sku : apple, qty : 10, price : 2.5 }, { sku : pears, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 7, cust_id : C, ord_date : ISODate(2023-06-20T00:00:00Z), price : 21, items : [ { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 9, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 51, items : [ { sku : carrots, qty : 5, price : 1 }, { sku : apples, qty : 10, price : 2.5 }, { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 1, cust_id : A, ord_date : ISODate(2023-06-01T00:00:00Z), price : 15, items : [ { sku : apple, qty : 5, price : 2.5 }, { sku : apples, qty : 5, price : 2.5 } ], status : 1 }
{ _id : 4, cust_id : B, ord_date : ISODate(2023-06-18T00:00:00Z), price : 26, items : [ { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 10, cust_id : D, ord_date : ISODate(2023-06-23T00:00:00Z), price : 23, items : [ { sku : apple, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 6, cust_id : C, ord_date : ISODate(2023-06-19T00:00:00Z), price : 38, items : [ { sku : carrots, qty : 10, price : 1 }, { sku : apples, qty : 10, price : 2.5 } ], status : 1 }
{ _id : 5, cust_id : B, ord_date : ISODate(2023-06-19T00:00:00Z), price : 40, items : [ { sku : banana, qty : 5, price : 10 } ], status : 1 }
{ _id : 8, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 76, items : [ { sku : banana, qty : 5, price : 10 }, { sku : apples, qty : 10, price : 2.5 } ], status : 1 }$unwind阶段
该阶段按 items 数组字段分解文档items为每个数组元素输出一个文档。例如
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { ord_date: { $gte: new Date(2023-03-01) } } },
... { $unwind: $items }
... ] )
{ _id : 2, cust_id : A, ord_date : ISODate(2023-06-08T00:00:00Z), price : 60, items : { sku : apple, qty : 8, price : 2.5 }, status : 1 }
{ _id : 2, cust_id : A, ord_date : ISODate(2023-06-08T00:00:00Z), price : 60, items : { sku : banana, qty : 5, price : 10 }, status : 1 }
{ _id : 3, cust_id : B, ord_date : ISODate(2023-06-08T00:00:00Z), price : 55, items : { sku : apple, qty : 10, price : 2.5 }, status : 1 }
{ _id : 3, cust_id : B, ord_date : ISODate(2023-06-08T00:00:00Z), price : 55, items : { sku : pears, qty : 10, price : 2.5 }, status : 1 }
{ _id : 7, cust_id : C, ord_date : ISODate(2023-06-20T00:00:00Z), price : 21, items : { sku : apple, qty : 10, price : 2.5 }, status : 1 }
{ _id : 9, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 51, items : { sku : carrots, qty : 5, price : 1 }, status : 1 }
{ _id : 9, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 51, items : { sku : apples, qty : 10, price : 2.5 }, status : 1 }
{ _id : 9, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 51, items : { sku : apple, qty : 10, price : 2.5 }, status : 1 }
{ _id : 1, cust_id : A, ord_date : ISODate(2023-06-01T00:00:00Z), price : 15, items : { sku : apple, qty : 5, price : 2.5 }, status : 1 }
{ _id : 1, cust_id : A, ord_date : ISODate(2023-06-01T00:00:00Z), price : 15, items : { sku : apples, qty : 5, price : 2.5 }, status : 1 }
{ _id : 4, cust_id : B, ord_date : ISODate(2023-06-18T00:00:00Z), price : 26, items : { sku : apple, qty : 10, price : 2.5 }, status : 1 }
{ _id : 10, cust_id : D, ord_date : ISODate(2023-06-23T00:00:00Z), price : 23, items : { sku : apple, qty : 10, price : 2.5 }, status : 1 }
{ _id : 6, cust_id : C, ord_date : ISODate(2023-06-19T00:00:00Z), price : 38, items : { sku : carrots, qty : 10, price : 1 }, status : 1 }
{ _id : 6, cust_id : C, ord_date : ISODate(2023-06-19T00:00:00Z), price : 38, items : { sku : apples, qty : 10, price : 2.5 }, status : 1 }
{ _id : 5, cust_id : B, ord_date : ISODate(2023-06-19T00:00:00Z), price : 40, items : { sku : banana, qty : 5, price : 10 }, status : 1 }
{ _id : 8, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 76, items : { sku : banana, qty : 5, price : 10 }, status : 1 }
{ _id : 8, cust_id : D, ord_date : ISODate(2023-06-20T00:00:00Z), price : 76, items : { sku : apples, qty : 10, price : 2.5 }, status : 1 }$group阶段
该阶段按 items.sku 进行分组计算每个 sku 的总数量。order _ids 数组包括不相同的 items.sku 元素。$addToSet 返回所有唯一值的数组这些值来自每个文档使用相同字段group by 的一组文档中。输出数组中元素的顺序未指定。
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { ord_date: { $gte: new Date(2023-03-01) } } },
... { $unwind: $items },
... { $group: { _id: $items.sku, qty: { $sum: $items.qty }, orders_ids: { $addToSet: $_id } } }
... ] )
{ _id : carrots, qty : 15, orders_ids : [ 6, 9 ] }
{ _id : apples, qty : 35, orders_ids : [ 1, 6, 9, 8 ] }
{ _id : banana, qty : 15, orders_ids : [ 8, 5, 2 ] }
{ _id : apple, qty : 63, orders_ids : [ 10, 1, 7, 4, 9, 2, 3 ] }
{ _id : pears, qty : 10, orders_ids : [ 3 ] }$project阶段
该阶段重塑输出文档以镜像映射缩减的输出使其具有两个字段_id和 value。运算符 $divide 计算 订单平均数量。 即将一个数字除以另一个数字并返回结果。将参数传递给在一个数组中。使用 $size 来确定数组orders_ids的大小。
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { ord_date: { $gte: new Date(2023-03-01) } } },
... { $unwind: $items },
... { $group: { _id: $items.sku, qty: { $sum: $items.qty }, orders_ids: { $addToSet: $_id } } },
... { $project: { value: { count: { $size: $orders_ids }, qty: $qty, avg: { $divide: [ $qty, { $size: $orders_ids } ] } } } }
... ] )
{ _id : apples, value : { count : 4, qty : 35, avg : 8.75 } }
{ _id : carrots, value : { count : 2, qty : 15, avg : 7.5 } }
{ _id : pears, value : { count : 1, qty : 10, avg : 10 } }
{ _id : banana, value : { count : 3, qty : 15, avg : 5 } }
{ _id : apple, value : { count : 7, qty : 63, avg : 9 } }$merge阶段 最后$merge将输出写入集合 agg_sku 。如果现有文档_id与新结果具有相同的键则该操作将覆盖现有文档。如果不存在具有相同键的现有文档则该操作将插入该文档。
sit_rs1:PRIMARY db.orders.aggregate( [
... { $match: { ord_date: { $gte: new Date(2023-03-01) } } },
... { $unwind: $items },
... { $group: { _id: $items.sku, qty: { $sum: $items.qty }, orders_ids: { $addToSet: $_id } } },
... { $project: { value: { count: { $size: $orders_ids }, qty: $qty, avg: { $divide: [ $qty, { $size: $orders_ids } ] } } } },
... { $merge: { into: agg_sku, on: _id, whenMatched: replace, whenNotMatched: insert } }
... ] )# 该操作返回以下文档
sit_rs1:PRIMARY db.agg_sku.find().sort( { _id: 1 } )
{ _id : apple, value : { count : 7, qty : 63, avg : 9 } }
{ _id : apples, value : { count : 4, qty : 35, avg : 8.75 } }
{ _id : banana, value : { count : 3, qty : 15, avg : 5 } }
{ _id : carrots, value : { count : 2, qty : 15, avg : 7.5 } }
{ _id : pears, value : { count : 1, qty : 10, avg : 10 } }聚合管道的限制
聚合管道对值类型和结果大小有一些限制: 该aggregate命令可以返回游标或将结果存储在集合中。结果集中的每个文档均受 16 MB BSON 文档大小限制。如果任何单个文档超过BSON 文档大小限制聚合就会产生错误。该限制仅适用于返回的文件。在管道处理过程中文档可能会超过此大小。该 db.collection.aggregate()方法默认返回一个游标。 每个单独的管道阶段的 RAM 限制为 100 MB。默认情况下如果某个阶段超过此限制MongoDB 会生成错误。$search 聚合阶段不限于 100 MB RAM因为它在单独的进程中运行 如果管道阶段之一的结果$sort超出限制请考虑添加 $limit stage 。