mongodb 聚合详解

        聚合(aggregate)框架提供一种方法来计算汇总值,虽然映射化简是强大的,但它往往比简单的汇总任务更困难,如字段值总和或平均值。MongoDB的聚合框架实现sum()、avg()、group by等聚合操作。通过聚合框架,还可对返回的结果进行处理,实现一些特殊需求,例如数据过滤、别名显示、增加字段、提取子字段等。

       1、聚合框架的基础

        管道和表达式

       1.1管道:

        集合管道从一个 管道运算符 流运文档到下一个的方式来处理文档。管道与unix管道类似,实质就是把扫描的数据输入聚合进程,进行一些过滤、分组、求和等操作,这些操作是通过管道操作符完成的。在管道中,管道运算符可以重复。所有的管道操作符都是处理文档流的,如果操作符扫描 collection 管道将起作用,并且将所有匹配的文档插入管道的”顶部”,管道里操作符转换通过管道的每个文档。管道操作符不需要为每一个输入文档生成一个输出文档:操作符也可能会产生新的文档或过滤文档。管道不能运算以下类型的值: Binary, Symbol, MinKey, MaxKey, DBRef, Code, 以及 CodeWScope。

       管道运算符:$project$match$limit$skip$unwind$group$sort

       $project:用于设定数据的筛选字段,就像我们SQL中select需要的字段一样。例子:

	db.runCommand({ aggregate : "article", pipeline : [
 	   { $match : { author : "dave" } },
	   { $project : {
	        _id : 0,
		author : 1,
	        tags : 1
	    }}
	]});

上面就是将所有author为dave的记录的author和tags两个字段取出来。(_id:0 表示去掉默认会返回的_id字段)。利用find()功能实现:

	> db.article.find({ author : "dave" }, { _id : 0, author : 1, tags : 1);
       $match:$match的作用是过滤数据,通过设置一个条件,将数据进行筛选过滤。例子:

	db.runCommand({ aggregate : "article", pipeline : [
	    { $match : { author : "dave" } }
	]});
这相当于将article这个collection中的记录进行筛选,筛选条件是author属性值为dave,其作用其实相当于普通的find命令,如:

	> db.article.find({ author : "dave" });

与find不同,find的结果是直接作为最终数据返回,而$match只是pipeline中的一环,它筛选的结果数据可以再进行下一级的统计操作。

       $limit:限制了的文档数量看一下由从当前位置开始的给定数。例子:

	>db.mycol.find({},{"title":1,_id:0}).limit(2)
	{"title":"MongoDB Overview"}
	{"title":"NoSQL Overview"}
	>

       $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。例子:

	>db.mycol.find({},{"title":1,_id:0}).limit(1).skip(1)
	{"title":"NoSQL Overview"}
	>
       $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。例子:

       比如你使用下面命令添加一条记录:

	db.article.save( {
	    title : "this is your title" ,
	    author : "dave" ,
	    posted : new Date(4121381470000) ,
	    pageViews : 7 ,
	    tags : [ "fun" , "nasty" ] ,
	    comments : [
	        { author :"barbara" , text : "this is interesting" } ,
	        { author :"jenny" , text : "i like to play pinball", votes: 10 }
	    ],
	    other : { bar : 14 }
	});
这里面tags字段就是一个array。下面我们在这个字段上应用$unwind操作

	db.runCommand({ aggregate : "article", pipeline : [
	    { $unwind : "$tags" }
	]});

         $group:按某一个key将key值相同的多条数据组织成一条。例子:

	db.runCommand({ aggregate : "article", pipeline : [
	    { $unwind : "$tags" },
	    { $group : {
		_id : "$tags",
	        count : { $sum : 1 },
		authors : { $addToSet : "$author" }
	    }}
	]});

         $sort:将输入文档排序后输出
        1.2表达式:
       表达式基于对输入文件进行计算而生成输出文件. 聚合框架定义表达式中使用的一种文件格式,使用前缀。表达式是无状态的,并只在被集合进程看到时才计算。管道里的   表达式只能操作当前文档,无法整合其他文档中的数据。

       表达式:$sum、$avg、$min、$max、$push、$addToSet、$first、$last
       $sum:总结从集合中的所有文件所定义的值。例子:

	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])

      $avg:从所有文档集合中所有给定值计算的平均。

	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])

      $min:获取集合中的所有文件中的相应值最小。

	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])

      $max:获取集合中的所有文件中的相应值的最大。

	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])

      $push:值插入到一个数组生成文档中。

	db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])

      $addToSet:值插入到一个数组中所得到的文档,但不会创建重复。

	db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])

      $first:根据分组从源文档中获取的第一个文档。通常情况下,这才有意义,连同以前的一些应用 “$sort”-stage。

	db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])

      $last:根据分组从源文档中获取最后的文档。通常,这才有意义,连同以前的一些应用 “$sort”-stage。

	db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

   2、聚合使用

        在 mongo 壳或者 数据库命令 aggregate 里使用 aggregate() 包装器调用 聚合`。通常在集合对象里调用 :method:`~db.collection.aggregate() 来决定集合 管道 输入文档。:method:~db.collection.aggregate() 方法的参数指定一系列 管道算子,其中每个操作符可以有许多操作数。

       数据:

{
   _id: ObjectId(7df78ad8902c)
   title: 'MongoDB Overview', 
   description: 'MongoDB is no sql database',
   by_user: 'w3cschool.cc',
   url: 'http://www.w3cschool.cc',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 100
},
{
   _id: ObjectId(7df78ad8902d)
   title: 'NoSQL Overview', 
   description: 'No sql database is very fast',
   by_user: 'w3cschool.cc',
   url: 'http://www.w3cschool.cc',
   tags: ['mongodb', 'database', 'NoSQL'],
   likes: 10
},
{
   _id: ObjectId(7df78ad8902e)
   title: 'Neo4j Overview', 
   description: 'Neo4j is no sql database',
   by_user: 'Neo4j',
   url: 'http://www.neo4j.com',
   tags: ['neo4j', 'database', 'NoSQL'],
   likes: 750
},

使用及结果:

> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
   "result" : [
      {
         "_id" : "w3cschool.cc",
         "num_tutorial" : 2
      },
      {
         "_id" : "Neo4j",
         "num_tutorial" : 1
      }
   ],
   "ok" : 1
}
>


$push 和$addToSet 区别

$addToSet同样可以向数组中添加元素,与$push不同的是$addToSet会保证元素的唯一性,利用$unwind可以在聚合中实现distinct的功能,这里是stackoverflow 上的一篇介绍,点击

mongodb中文社区


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值