企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] # mongo与mysql聚合类比 ![](https://box.kancloud.cn/faf3323ae66292c77226d250b9c00ba4_287x466.png) 下面举了一些常用的mongo聚合例子和mysql对比,假设有一条如下的数据库记录(表名:orders)作为例子: ~~~ { cust_id: "abc123", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: 'A', price: 50, items: [ { sku: "xxx", qty: 25, price: 1 }, { sku: "yyy", qty: 25, price: 1 } ] } ~~~ **统计orders表所有记录** ~~~ db.orders.aggregate( [ { $group: { _id: null, count: { $sum: 1 } } } ] ) 类似mysql: SELECT COUNT(*) AS count FROM orders ~~~ **对orders表计算所有price求和** ~~~ db.orders.aggregate( [ { $group: { _id: null, total: { $sum: "$price" } } } ] ) 类似mysql; SELECT SUM(price) AS total FROM orders ~~~ **对每一个唯一的cust\_id, 计算price总和** ~~~ db.orders.aggregate( [ { $group: { _id: "$cust_id", total: { $sum: "$price" } } } ] ) 类似mysql: SELECT cust_id, SUM(price) AS total FROM orders GROUP BY cust_id ~~~ **对每一个唯一对cust\_id和ord\_date分组,计算price总和,不包括日期的时间部分** ~~~ db.orders.aggregate( [ { $group: { _id: { cust_id: "$cust_id", ord_date: { month: { $month: "$ord_date" }, day: { $dayOfMonth: "$ord_date" }, year: { $year: "$ord_date"} } }, total: { $sum: "$price" } } } ] ) 类似mysql: SELECT cust_id, ord_date, SUM(price) AS total FROM orders GROUP BY cust_id, ord_date ~~~ **对于有多个记录的cust\_id,返回cust\_id和对应的数量** ~~~ db.orders.aggregate( [ { $group: { _id: "$cust_id", count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } } ] ) 类似mysql: SELECT cust_id, count(*) FROM orders GROUP BY cust_id HAVING count(*) > 1 ~~~ **对每个唯一的cust\_id和ord\_date分组,计算价格总和,并只返回price总和大于250的记录,且排除日期的时间部分** ~~~ db.orders.aggregate( [ { $group: { _id: { cust_id: "$cust_id", ord_date: { month: { $month: "$ord_date" }, day: { $dayOfMonth: "$ord_date" }, year: { $year: "$ord_date"} } }, total: { $sum: "$price" } } }, { $match: { total: { $gt: 250 } } } ] ) 类似mysql: SELECT cust_id, ord_date, SUM(price) AS total FROM orders GROUP BY cust_id, ord_date HAVING total > 250 ~~~ **对每个唯一的cust\_id且status=A,计算price总和** ~~~ db.orders.aggregate( [ { $match: { status: 'A' } }, { $group: { _id: "$cust_id", total: { $sum: "$price" } } } ] ) 类似mysql: SELECT cust_id, SUM(price) as total FROM orders WHERE status = 'A' GROUP BY cust_id ~~~ **对每个唯一的cust\_id且status=A,计算price总和并且只返回price总和大于250的记录** ~~~ db.orders.aggregate( [ { $match: { status: 'A' } }, { $group: { _id: "$cust_id", total: { $sum: "$price" } } }, { $match: { total: { $gt: 250 } } } ] ) 类似mysql: SELECT cust_id, SUM(price) as total FROM orders WHERE status = 'A' GROUP BY cust_id HAVING total > 250 ~~~ **对于每个唯一的cust\_id,将与orders相关联的相应订单项order\_lineitem的qty字段进行总计** ~~~ db.orders.aggregate( [ { $unwind: "$items" }, { $group: { _id: "$cust_id", qty: { $sum: "$items.qty" } } } ] ) 类似mysql: SELECT cust_id, SUM(li.qty) as qty FROM orders o, order_lineitem li WHERE li.order_id = o.id GROUP BY cust_id ~~~ **统计不同cust\_id和ord\_date分组的数量,排除日期的时间部分** ~~~ db.orders.aggregate( [ { $group: { _id: { cust_id: "$cust_id", ord_date: { month: { $month: "$ord_date" }, day: { $dayOfMonth: "$ord_date" }, year: { $year: "$ord_date"} } } } }, { $group: { _id: null, count: { $sum: 1 } } } ] ) 类似mysql: SELECT COUNT(*) FROM (SELECT cust_id, ord_date FROM orders GROUP BY cust_id, ord_date) as DerivedTable ~~~ # aggregate db.collection.aggregate()是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。 通过这张图,可以了解Aggregate处理的过程。 ![](https://box.kancloud.cn/1db1bf7c63d0edd4b02cae13043851fe_701x507.png) 1. db.collection.aggregate() 可以用多个构件创建一个管道,对于一连串的文档进行处理。这些构件包括:筛选操作的match、映射操作的project、分组操作的group、排序操作的sort、限制操作的limit、和跳过操作的skip。 2. db.collection.aggregate()使用了MongoDB内置的原生操作,聚合效率非常高,支持类似于SQL Group By操作的功能,而不再需要用户编写自定义的JavaScript例程。 3. 每个阶段管道限制为100MB的内存。如果一个节点管道超过这个极限,MongoDB将产生一个错误。为了能够在处理大型数据集,可以设置allowDiskUse为true来在聚合管道节点把数据写入临时文件。这样就可以解决100MB的内存的限制。 4. db.collection.aggregate()可以作用在分片集合,但结果不能输在分片集合,MapReduce可以 作用在分片集合,结果也可以输在分片集合。 5. db.collection.aggregate()方法可以返回一个指针(cursor),数据放在内存中,直接操作。跟Mongo shell 一样指针操作。 6. db.collection.aggregate()输出的结果只能保存在一个文档中,BSON Document大小限制为16M。可以通过返回指针解决,版本2.6中后面:DB.collect.aggregate()方法返回一个指针,可以返回任何结果集的大小。