1>、聚合框架:使用聚合框架可以对集合中的文档进行变换和组合。基本上,可以用多个构件创建一个管道(pipeline),用于对一连串的文档进行处理。这些构件包括筛选(filtering)、投射(projecting)、分组(grouping)、排序(sorting)、限制(limiting)和跳过(skipping)。

2>、管道操作符:每个操作符都会接受一连串的文档,对这些文档做一些类型转换,最后将转换后的文档作为结果传递给下一个操作符(对于最后一个管道操作符,是将结果返回给客户端)。不同的管道操作符可以按任意顺序组合在一起使用,而且可以被重复任意多次。1、$match:用于对文档集合进行筛选,之后就可以在筛选得到的文档子集上做聚合。在实际使用中应该尽可能将$match放在管道的前面位置,这样做有两个好处:一是可以快速将不需要的文档过滤掉,以减少管道的工作量;二是如果在投射和分组之前执行$match,查询可以使用索引。2、$project:使用$project可以从子文档中提取字段,可以重命名字段,可以指定包含或者不包含一个字段,还可以在这些字段上进行一些有意思的操作。$project操作是从文档选择想要的字段,可以指定包含或者不包含的一个字段。也可以将投射过得字段进行重命名。db.users.aggregate({$project:{"userId":"$_id","_id":0}})结果如下:{result:[{userId:ObjectId("xxx")}]}。重命名时必须明确指出将要重命名的字段排除(如上例中_id:0),否则这个字段的值会被返回两次:一次被标为重命名后的名字(如userId),一次被标为命名前的(如_id)。可以使用这种技术生成字段的多个副本,以便在之后的$group中使用。在对字段进行重命名时,mongodb并不会记录字段的历史名称,因此,应该尽量在修改字段名称之前使用索引。

3>、表达式:1、算术表达式可用于操作数值:.$add:[expr1[,expr2...,exprn]],接受一个或多个表达式作为参数,将这些表达式相加的和作为结果;.$subtract:[expr1,expr2]接受两个参数,用第一个表达式减去第二个表达式作为结果,将差作为结果;.$multiply:[expr1[,expr2...,exprn]]将表达式的值相乘;.$divide:[expr1,expr2],用第一个表达式除以第二个表达式的商作为结果;.$mod:[expr1,expr2],将第一个表达式除以第二个表达式得到的余数作为结果。2、日期表达式:$year、$month、$week、$dayOfMonth、$dayOfWeek、$dayOfYear、$minute、$second,只能对日期类型的字段进行操作,每种日期类型的操作都是类似的:接受一个日期表达式,返回一个数值。3、字符串表达式:$substr:[expr,startOffset,numToReturn],第一个参数expr必须是字符串,这个操作符将会截取字符串的子串(从startOffset字节开始的numToReturn字节,不是字符);$concat:[expr1[,expr2...,exprN],将给定的表达式连接在一起作为结果返回;$toLower:expr,参数expr必须是字符串值,返回小写形式;$toUpper:expr,参数expr必须是字符串值,返回大写形式。4、逻辑表达式:$cmp:[expr1,expr2],比较expr1和expr2。如果expr1等于expr2,返回0;如果expr1<expr2,返回一个负数;如果expr1>expr2,返回一个正数;$strcasecmp:[string1,string2],比较string1和string2,区分大小写;$eq/$ne/$gt/$gte/$lt/$lte:[expr1,expr2],返回比较的结果(true或false);$and:[expr1[,expr2...,exprN]],如果表达式的值都是true,返回true,否则返回false;$or:[expr1[,expr2...,exprN]],只要有任意表达式的值为true,就返回true,否则返回false;$not:expr,对expr取反;$cond:[booleanExpr,trueExpr,flaseExpr],如果booleanExpr的值为true,返回trueExpr,否则返回flaseExpr;$ifNull:[expr,replacementExpr],如果expr是null,返回replacementExpr,否则返回expr。5、$group:$group操作可以将文档依据特定字段的不同值进行分组,它不能对流式工作方式的文档进行处理,必须要等收到所有的文档之后,才能对文档进行分组。$sum:value,对于分组中的每一个文档,将value与计算结果相加;$avg:value返回每个分组的平均值;$max:expr,返回分组内的最大值;$min:expr,返回分组内的最小值;$frist:expr返回分组的第一个值,忽略后面的所有值;$last:expt返回分组的最后一个值。数组操作符:有两个操作符可以进行数组操作,$addToSet:expr,如果当前数组中不包含expr,就将它添加到数组中,再返回的结果集中,每个元素最大只出现一次,而且元素的顺序是不确定的;$push:expr,不管expr是什么值,都将添加到数组中,返回包含所有值得数组。6、$unwind(拆分):可以将数组中的每一个值拆分为单独的文档。如果希望在查询中得到特定的子文档,这个操作符就会非常有用:先使用$unwind得到所有的子文档,在使用$match得到想要的文档。$sort可以根据任何字段进行排序,排序方向可以是1(升序)和-1(降序)。$limit(n):返回结果集中的前n个文档。$skip(n):跳过结果集中的前n个文档,将剩余的文档作为结果返回。应该尽量在管道的开始阶段(执行$project、$group、$unwind操作之前)就将尽可能多的文档和字段过滤掉。管道如果不是直接从原先的集合中使用数据,那就无法在筛选和排序中使用索引,如果可能,聚合管道会尝试对操作进行排序,以便能够有效的使用索引。mongodb不允许单一的聚合操作占用过多的系统内存:如果mongodb发现某个聚合操作占用了20%以上的内存,这个操作就会直接输出错误。如果能够通过$match操作迅速减小结果集的大小,就可以使用管道进行实施聚合。由于管道会不断包含更多的文档,会越来越复杂,所以几乎不可能呢实时得到管道的操作结果。

4>、MapReduce:MapReduce能够在多台服务器之间并行执行,它会将一个大问题拆分为多个小问题,将各个小问题发送到不同的机器上,每台机器只负责完成一部分工作,所有机器都完成时,再将这些零碎的解决方案合并为一个完整的解决方案。MapReduce需要几个步骤:首先是映射(map),将操作映射到集合中的每个文档,这个操作要么“无作为”,要么“产生一些键和X个值”;然后是中间环节,称作洗牌(shuffle),按照键分组,并将产生的键值组成列表放到对应的键中;最后化简(reduce)则把列表中的值化简成一个单值,这个值被返回,然后接着进行洗牌,知道每个键的列表只有一个值为止,这个值也就是最终的结果。命令语法:

db.runCommand(

 { mapreduce : 字符串集合名,
   map : 函数,
   reduce : 函数,
   [, query : 文档,发往map函数前先给过渡文档]
   [, sort : 文档,发往map函数前先给文档排序]
   [, limit : 整数,发往map函数的文档数量上限]
   [, out : 字符串,统计结果保存的集合]
   [, keeptemp: 布尔值,链接关闭时临时结果集合是否保存]
   [, finalize : 函数,将reduce的结果送给这个函数,做最后的处理]
   [, scope : 文档,js代码中要用到的变量]
   [, jsMode : 布尔值,是否减少执行过程中BSON和JS的转换,默认true] //注:false时 BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可处理非常大的mapreduce,<br>                                    //true时BSON-->js-->map-->reduce-->BSON
   [, verbose : 布尔值,是否产生更加详细的服务器日志,默认true]
 }
);

说明:finalize:function可以将reduce的结果发送给这个键,这是整个处理过程的最后一步,它会在最后一个reduce输出结果后执行,然后将结果存到临时集合中,通常来说,finalize是计算平均数、裁剪数组、清楚多余信息的好时机;keeptemp:boolean如果值为true,那么在连接关闭时会将临时结果集合保存下来,否则不保存;out:string输出集合的名称,如果设置了这个选项,系统会自动设置keeptemp:true,默认情况下,mongo会在执行MapReduce时创建一个临时集合,集合名是系统选的一个不太常用的名字,将"mr"、执行MapReduce的集合名、时间戳以及数据库作业ID,用"."连成一个字符串,这就是临时集合的名字,mongodb会在调用的连接关闭时自动销毁这个集合,可以用out选项为临时集合指定一个易读易懂的名字,但是即便你取了一个非常好的名字,mongodb也会在MapReduce的中间过程使用自动生成的集合名,处理完成后,会自动将临时集合的名字更改为你指定的集合名;query:document在发往map函数前,先用指定条件过滤文档;sort:document在发往map前先给文档排序(与limit一同使用非常有用);limit:integer发往map函数的文档数量的上限;scope:document可以再JavaScript代码中使用的变量;verbose:boolean是否记录详细的服务器日志。

例如:

>mr=db.runCommand({mapreduce:"foo",map:map,reduce:reduce})
{  
  result:"tmr.mr.mapreduce_1266787811_1",
  timeMillis:12,
  count:{
    input:6,
    emit:14,
    output:5
  },
  ok:true

}MapReduce返回的文档包含很多与操作有关的元信息:result这是存放MapReduce结果的集合名,这是个临时集合,MapReduce的连接关闭后它就被自动删除了;timeMillis操作话费的时间;counts这个内嵌文档主要用作调试,其中包含3个键:input发送到map函数的文档个数,emit在map函数中emit被调用的次数,output结果集合中的文档数量。有时需要对集合的一部分执行MapReduce,只需在传给map函数前使用查询对文档进行过滤就好了,每个传递给map函数的文档都要先反序列化,从BSON对象转换为JavaScript对象。

 

5>、聚合命令:count()用于返回集合中文档的数量,不论集合有多大,count都会很快返回总的文档数量,也可以给count传递一个查询文档,mongo会计算查询结果的数量;distinct用来找出给定键的所有不同值,使用时必须指定集合和键,例如:db.runCommand({distinct:"people",key:"age"})。group可以执行更复杂的聚合,先选定分组所依据的键,而后mongodb就会将集合依据选定键的不同值分成若干组,然后可以对每一个分组内的文档进行聚合,得到一个结果文档。

db.collection.group({
	key:{field:1},//按什么字段进行分组
	initial:{count:0},//进行分组前变量初始化,该处声明的变量可以在以下回调函数中作为result的属性使用
	cond:{},//类似mysql中的having,分组后的查询返回
	$reduce: function ( curr, result ) { }, //The function takes two arguments: the current document and an aggregation result document for that group.先迭代出分组,然后再迭代分组中的文档,即curr变量就代表当前分组中此刻迭代到的文档,result变量就代表当前分组。
      $keyf:function(doc){},//keyf和key二选一,传入的参数doc代表当前文档,如果分组的字段是经过运算后的字段用到,作用类似mysql中的group by left('2015-09-12 14:05:22',10);
      finalize:function(result) {}//该result也就是reduce的result,都是代表当前分组,这个函数是在走完当前分组结束后回调;
})