MongoDB聚合框架的简单介绍

聚合框架

使用聚合框架可以对集合中的文档进行变换和组合。可以用多个构件创建一个管道(pipeline,类似一个流),用于对一连串的文档进行处理。这些构件包括:

  • 筛选(filtering)

  • 投射(projecting)

  • 分组(grouping)

  • 排序(sorting)

  • 限制(limiting)

  • 跳过(skipping)

聚合的结果必须要限制在16M之内(MongoDB支持的最大的响应大小)。

要将每个操作传给aggreagte()函数。

db.集合.aggregate(构件1,构件2…)

//有一个保存着杂志文章的集合,找出发表文章最多的那个作者
db.articles.aggregate({$project:{"author":1}},${$group:{"_id":"$author","count":{"$sum":1}}},{$sort:{"count":-1}},{$limit:5})

每个操作符都会接受一连串的文档,对这些文档做一些操作,最后将转换后的文档作为结果传递给下一个操作符(最后一个操作符是将结果返回给客户端)

不同的管道操作符可以按任意组合任意顺序一起使用,而且可以被重复多次使用。

管道操作符

1、$match

$match用于对文档进行筛选,可以使用所有常规的查询操作符 。

//查询性别为男的用户
{$match:{"sex":"男"}}
//查询工资为10000以上的员工
{$match:{"saler":{$gt:10000}}}

应该尽可能将“$match”放在管道的前面:

  • 一是可以快速将不需要的文档过滤掉,减少管道的工作量
  • 二是在投射和分组之前执行“$match”,查询可以使用索引

2、$project

使用”$project”可以从文档中提取字段(只返回想要的字段),可以重命名字段.

1、从文档中选择想要的字段,可以指定包含或不包含一个字段

//指定只返回author字段(默认都包含“_id”字段,必须显式声明"_id":0,才不包含"_id"字段)
db.articles.aggregate({$project:{"author":1}})

2、将字段重命名

//将每个用户文档的"_id"再返回结果中重命名为"userId"
db.users.aggregate({$project:{"userId":"$_id","_id":0}})
{ "userId" : ObjectId("5b3c7f2020306147a4f53537") }
//必须明确指定将"_id"排除,否则会出现下面这种结果
{ "_id":ObjectId("5b3c7f2020306147a4f53537"), "userId" : ObjectId("5b3c7f2020306147a4f53537") }
//”$fieldname“语法是为了在聚合框架中引用fieldname字段的值,例如 ”$age“会被替换为"age"字段的内容,上面的"$_id"会被替换为进入管道的问个文档的"_id"字段的值

在字段进行重命名时,MongoDB不会记录字段的历史名称,即在”id”字段上有索引,重命名成”userId”后,在之后的操作中不能使用“_id”的索引。所以尽量在修改字段名称前使用索引。

3、$group

group可以将文档根据特定字段的不同值进行分组,将分组的字段传递给”group”函数的”_id”字段

//按课程分组
{$group:{"_id":"course"}}
//按成绩分组
{$group:{"_id":"grade"}}

$group可以使用的操作符:

1: s u m : v a l u e v a l u e 2 avg:value :返回每个分组的平均值
3: m a x : e x p r 4 min:expr :返回分组内的最小值
5: f i r s t : e x p r 6 last:expr :与上面一个相反,返回分组的最后一个值
7: a d d T o S e t : e x p r e x p r 8 push:expr:把expr加入到数组中

3、$unwind

$unwind可以将数组中的每一个值拆分为单独的文档。

//一篇有多条评论的文章,可以使用$unwind将每条评论拆分为一个独立的文档
db.blog.findOne()
{
    "_id" : ObjectId("5b3dceb8eb560553b80bf190"),
    "content" : "...",
    "author" : "wang",
    "comments" : [
        {
            "comment" : "good post",
            "author" : "John",
            "votes" : 0
        },
        {
            "comment" : "i thought it was too short",
            "author" : "Claire",
            "votes" : 3
        },
        {
            "comment" : "free watch",
            "author" : "Alice",
            "votes" : -1
        }
    ]
}

db.blog.aggregate({$unwind:"$comments"})
{
    "_id" : ObjectId("5b3dceb8eb560553b80bf190"),
    "content" : "...",
    "author" : "wang",
    "comments" : {
        "comment" : "good post",
        "author" : "John",
        "votes" : 0
    }
}
{
    "_id" : ObjectId("5b3dceb8eb560553b80bf190"),
    "content" : "...",
    "author" : "wang",
    "comments" : {
        "comment" : "i thought it was too short",
        "author" : "Claire",
        "votes" : 3
    }
}
{
    "_id" : ObjectId("5b3dceb8eb560553b80bf190"),
    "content" : "...",
    "author" : "wang",
    "comments" : {
        "comment" : "free watch",
        "author" : "Alice",
        "votes" : -1
    }
}
//查询特定子文档
//只想要作者为“Alice”的评论,不想要其他的信息
db.blog.aggregate({$project:{"_id":0,"comments":"$comments"}},{$unwind:"$comments"},{$match:{"comments.author":"Alice"}})

4、$sort

$sort可以根据一个或多个字段排序

5、$limit

$limit会接受一个数字n,返回结果集中的前n个文档

6、$skip

$skip接受一个数字n,丢掉结果集中的前n个文档,将剩余文档返回结果集。

示例:

//准备示例数据
for(var i=0;i<100;i++){
    for(var j=0;j<4;j++){
        db.scores.insert({"studentId":"s"+i,"course":"课程"+j,"score":Math.random()*100});
    }
}
//找出考80分以上的课程门数最多的5个学生

步骤:
1、找出所有考了80分以上的学生,不区分课程
{$match:{"score":{$gte:80}}}
2、将每个学生的名字投影出来
{$project:{"studentId":1}}
3、对学生的名字分组,某个学生的名字出现一次,给他加1
{$group:{"_id":"$studentId","count":{$sum:1}}}
4、对结果集按照count进行降序排序
{$sort:{"count":-1}}
5、返回前面的5条数据
{$limit:5}

最终语句
db.scores.aggregate({$match:{"score":{$gte:80}}},
                    {$project:{studentId:1}},
                    {$group:{"_id":"$studentId","count":{$sum:1}}},
                    {$sort:{"count":-1}},{$limit:5}
)
result:
{ "_id" : "s17", "count" : 3 }
{ "_id" : "s42", "count" : 3 }
{ "_id" : "s0", "count" : 3 }
{ "_id" : "s4", "count" : 3 }
{ "_id" : "s7", "count" : 3 }

猜你喜欢

转载自blog.csdn.net/wangbing25307/article/details/80930476