一、MongoDB聚合
聚合操作处理数据记录并返回计算结果。聚合操作将来自多个文档的值组合在一起,并且可以对分组数据执行各种操作以返回单个结果。MongoDB提供了三种执行聚合的方式:聚合管道,map-reduce函数和单用途聚合方法。
1、单用途聚合操作
MongoDB了提供db.collection.estimatedDocumentCount(), db.collection.count()和db.collection.distinct()。
所有这些操作都聚合来自单个集合的文档。虽然这些操作提供了对公共聚合过程的简单访问,但它们缺乏聚合管道和map-reduce的灵活性和功能。
(1)db.collection.estimatedDocumentCount()
返回集合或视图中所有文档的计数
示例:检索orders集合中所有文档的计数
> db.orders.find() //orders集合
{ "_id" : ObjectId("5d3e560d55ad906481cb2ecc"), "cust_id" : "abc123", "status" : "A", "price" : 50, "items" : [ { "sku" : "xxx", "qty" : 25, "price" : 1 }, { "sku" : "yyy", "qty" : 25, "price" : 1 } ] }
{ "_id" : ObjectId("5d3e570e55ad906481cb2ecd"), "cust_id" : "def456", "status" : "A", "price" : 50, "items" : [ { "sku" : "zzz", "qty" : 25, "price" : 1 }, { "sku" : "www", "qty" : 25, "price" : 1 } ] }
{ "_id" : ObjectId("5d3e573955ad906481cb2ece"), "cust_id" : "ghi789", "status" : "B", "price" : 100, "items" : [ { "sku" : "xxx", "qty" : 25, "price" : 1 }, { "sku" : "yyy", "qty" : 25, "price" : 1 } ] }
{ "_id" : ObjectId("5d3e587855ad906481cb2ecf"), "cust_id" : "abc123", "status" : "A", "price" : 70, "items" : [ { "sku" : "xxx", "qty" : 25, "price" : 1 }, { "sku" : "yyy", "qty" : 25, "price" : 1 } ] }
> db.orders.estimatedDocumentCount({})
4
(2)db.collection.count()
返回与find()集合或视图的查询匹配的文档计数 。该 db.collection.count()方法不执行 find()操作,而是计算并返回与查询匹配的结果数。
需要注意的是,在分片群集上,如果存在孤立文档或 正在进行块迁移,则db.collection.count()没有查询谓词可能导致计数 不准确。要避免这些情况,请在分片群集上使用 db.collection.aggregate()方法。
示例:计算orders集合中的所有文档
> db.orders.count()
4
count()等同于 db.collection.find(query).count()构造。以上操作等同于:
> db.orders.find().count()
4
示例:计算与查询匹配的所有文档
> db.orders.count({price : {$gt : 50}})
2
> db.orders.find({price : {$gt : 50}}).count() //这两个查询等效
2
(3)db.collection.distinct()
在单个集合或视图中查找指定字段的不同值,并在数组中返回结果。
> db.orders.distinct("cust_id") //返回不同cust_id的数组
[ "abc123", "def456", "ghi789" ]
> db.orders.distinct("items.sku") //返回items字段中嵌入字段sku的数组
[ "xxx", "yyy", "www", "zzz" ]
> db.orders.distinct("price",{status : "A"}) //返回status字段为“A”,price字段不同值的数组
[ 50, 70 ]
2、Aggregation Pipeline聚合管道
db.collection.aggregate()是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。
通过这张图,可以了解Aggregate处理的过程:
在这张图中:
第一阶段:$match阶段按status字段过滤文档,并将那些status等于A的文档传递给下一阶段;
第二阶段:$group阶段按cust_id字段对文档进行分组,以计算每个唯一cust_id的数量总和。
aggregate常用pipeline stage介绍:
(1)$count
返回包含输入到stage的文档的计数,理解为返回与表或视图的find()查询匹配的文档的计数。db.collection.count()方法不执行find()操作,而是计数并返回与查询匹配的结果数。
> db.orders.find() //演示集合
{ "_id" : ObjectId("5d3e560d55ad906481cb2ecc"), "cust_id" : "abc123", "status" : "A", "price" : 50, "items" : [ { "sku" : "xxx", "qty" : 25, "price" : 1 }, { "sku" : "yyy", "qty" : 25, "price" : 1 } ] }
{ "_id" : ObjectId("5d3e570e55ad906481cb2ecd"), "cust_id" : "def456", "status" : "A", "price" : 50, "items" : [ { "sku" : "zzz", "qty" : 25, "price" : 1 }, { "sku" : "www", "qty" : 25, "price" : 1 } ] }
{ "_id" : ObjectId("5d3e573955ad906481cb2ece"), "cust_id" : "ghi789", "status" : "B", "price" : 100, "items" : [ { "sku" : "xxx", "qty" : 25, "price" : 1 }, { "sku" : "yyy", "qty" : 25, "price" : 1 } ] }
{ "_id" : ObjectId("5d3e587855ad906481cb2ecf"), "cust_id" : "abc123", "status" : "A", "price" : 70, "items" : [ { "sku" : "xxx", "qty" : 25, "price" : 1 }, { "sku" : "yyy", "qty" : 25, "price" : 1 } ] }
> db.orders.aggregate([
... {$match : {price : {$gt:50}}}, //$match 阶段排除price小于等于50的文档,符合的文档传到下个阶段
... {$count : "High_price"} //$count阶段返回聚合管道中剩余文档的计数,并将该值分配给名为High_price的字段
... ])
{ "High_price" : 2 }
该$count阶段相当于以下