通过上一篇文章中,认识了MongoDB中四个聚合操作,提供基本功能的count、distinct和group,还有可以提供强大功能的mapReduce。

在MongoDB的2.2版本以后,聚合框架中多了一个新的成员,聚合管道,数据进入管道后就会经过一级级的处理,直到输出。

对于数据量不是特别大,逻辑也不是特别复杂的聚合操作,聚合管道还是比mapReduce有很多优势的:

  1. 相比mapReduce,聚合管道比较容易理解和使用
  2. 可以直接使用管道表达式操作符,省掉了很多自定义js function,一定程度上提高执行效率
  3. 和mapReduce一样,它也可以作用于分片集合

但是,对于数据量大,逻辑复杂的聚合操作,还是要使用mapReduce实现。

聚合管道

在聚合管道中,每一步操作(管道操作符)都是一个工作阶段(stage),所有的stage存放在一个array中。MongoDB文档中的描述如下:

db.collection.aggregate( [ { <stage> }, ... ] )

在聚合管道中,每一个stage都对应一个管道操作符,根据MongoDB文档,聚合管道可以支持以下管道操作符:

Name

Description

$geoNear

Returns an ordered stream of documents based on the proximity to a geospatial point. Incorporates the functionality of $match, $sort, and $limit for geospatial data. The output documents include an additional distance field and can include a location identifier field.

$group

Groups input documents by a specified identifier expression and applies the accumulator expression(s), if specified, to each group. Consumes all input documents and outputs one document per each distinct group. The output documents only contain the identifier field and, if specified, accumulated fields.

$limit

Passes the first n documents unmodified to the pipeline where n is the specified limit. For each input document, outputs either one document (for the first n documents) or zero documents (after the first n documents).

$match

Filters the document stream to allow only matching documents to pass unmodified into the next pipeline stage. $match uses standard MongoDB queries. For each input document, outputs either one document (a match) or zero documents (no match).

$out

Writes the resulting documents of the aggregation pipeline to a collection. To use the $out stage, it must be the last stage in the pipeline.

$project

Reshapes each document in the stream, such as by adding new fields or removing existing fields. For each input document, outputs one document.

$redact

Reshapes each document in the stream by restricting the content for each document based on information stored in the documents themselves. Incorporates the functionality of $project and $match. Can be used to implement field level redaction. For each input document, outputs either one or zero document.

$skip

Skips the first n documents where n is the specified skip number and passes the remaining documents unmodified to the pipeline. For each input document, outputs either zero documents (for the first n documents) or one document (if after the first n documents).

$sort

Reorders the document stream by a specified sort key. Only the order changes; the documents remain unmodified. For each input document, outputs one document.

$unwind

Deconstructs an array field from the input documents to output a document for each element. Each output document replaces the array with an element value. For each input document, outputs n documents where n is the number of array elements and can be zero for an empty array.

下面通过具体的例子看看聚合管道的基本用法:

首先,通过以下代码准备测试数据:

 var dataList = [
{ "name" : "Will0", "gender" : "Female", "age" : , "classes": ["MongoDB", "C#", "C++"]},
{ "name" : "Will1", "gender" : "Female", "age" : , "classes": ["Node", "JavaScript"]},
{ "name" : "Will2", "gender" : "Male", "age" : , "classes": ["Java", "WPF", "C#"]},
{ "name" : "Will3", "gender" : "Male", "age" : , "classes": ["WPF", "C",]},
{ "name" : "Will4", "gender" : "Male", "age" : , "classes": ["SQL", "HTML"]},
{ "name" : "Will5", "gender" : "Male", "age" : , "classes": ["DOM", "CSS", "HTML5"]},
{ "name" : "Will6", "gender" : "Female", "age" : , "classes": ["PPT", "Word", "Excel"]},
{ "name" : "Will7", "gender" : "Female", "age" : , "classes": ["HTML5", "C#"]},
{ "name" : "Will8", "gender" : "Male", "age" : , "classes": ["Java", "VB", "BASH"]},
{ "name" : "Will9", "gender" : "Female", "age" : , "classes": ["CSS"]}
] for(var i = ; i < dataList.length; i++){
db.school.students.insert(dataList[i]);
}

$project

$project主要用于数据投影,实现字段的重命名、增加和删除。下面例子中,重命名了"name"字段,增加了"birthYear"字段,删除了"_id"字段。

 > db.runCommand({
... "aggregate": "school.students",
... "pipeline": [
... {"$match": {"age": {"$lte": }}},
... {"$project": {"_id": , "studentName": "$name", "gender": , "birthYear": {"$subtract": [, "$age"]}}},
... {"$sort": {"birthYear":}}
... ]
... })
{
"result" : [
{
"gender" : "Female",
"studentName" : "Will0",
"birthYear" :
},
{
"gender" : "Male",
"studentName" : "Will4",
"birthYear" :
},
{
"gender" : "Male",
"studentName" : "Will8",
"birthYear" :
},
{
"gender" : "Female",
"studentName" : "Will1",
"birthYear" :
},
{
"gender" : "Male",
"studentName" : "Will5",
"birthYear" :
},
{
"gender" : "Female",
"studentName" : "Will6",
"birthYear" :
}
],
"ok" :
}
>

$unwind

$unwind用来将数组拆分为独立字段。

 > db.runCommand({
... "aggregate": "school.students",
... "pipeline": [
... {"$match": {"age": }},
... {"$project": {"name": , "gender": , "age": , "classes": }},
... {"$unwind": "$classes"}
... ]
... })
{
"result" : [
{
"_id" : ObjectId("54805220e31c9e1578ed0ccc"),
"name" : "Will3",
"gender" : "Male",
"age" : ,
"classes" : "WPF"
},
{
"_id" : ObjectId("54805220e31c9e1578ed0ccc"),
"name" : "Will3",
"gender" : "Male",
"age" : ,
"classes" : "C"
}
],
"ok" :
}
>

$group

跟单个的group用法类似,用作分组操作。

使用$group时,必须要指定一个_id域,同时也可以包含一些算术类型的表达式操作符。

下面的例子就是用聚合管道实现得到男生和女生的平均年龄。

 > db.runCommand({
... "aggregate": "school.students",
... "pipeline": [
... {"$group":{"_id":"$gender", "avg": { "$avg": "$age" } }}
... ]
... })
{
"result" : [
{
"_id" : "Male",
"avg" : 21.8
},
{
"_id" : "Female",
"avg" :
}
],
"ok" :
}
>

查询男生和女生的最大年龄

 > db.runCommand({
... "aggregate": "school.students",
... "pipeline": [
... {"$group": {"_id": "$gender", "max": {"$max": "$age"}}}
... ]
... })
{
"result" : [
{
"_id" : "Male",
"max" :
},
{
"_id" : "Female",
"max" :
}
],
"ok" :
}
>

管道操作符、管道表达式和表达式操作符

上面的例子中,已经接触了这几个概念,下面进行进一步介绍。

管道操作符作为"键",所对应的"值"叫做管道表达式,例如"{"$group": {"_id": "$gender", "max": {"$max": "$age"}}}"

  • $group是管道操作符
  • {"_id": "$gender", "max": {"$max": "$age"}}是管道表达式
  • $gender在文档中叫做"field path",通过"$"符号来获得特定字段,是管道表达式的一部分
  • $max是表达式操作符,正是因为聚合管道中提供了很多表达式操作符,我们可以省去很多自定义js函数

下面列出了常用的表达式操作符,更详细的信息,请参阅MongoDB文档

  • Boolean Expressions
    • $and, $or, $ not
  • Comparison Expressions
    • $cmp, $eq, $gt, $gte, $lt, $lte, $ne
  • Arithmetic Expressions
    • $add, $divide, $mod, $multiply, $subtract
  • String Expressions
    • $concat, $strcasecmp, $substr, $toLower, $toUpper

总结

聚合管道提供了一种mapReduce 的替代方案,mapReduce使用相对来说比较复杂,而聚合管道的拥有固定的接口,一系列可选择的表达式操作符,对于大多数的聚合任务,聚合管道一般来说是首选方法。

Ps: 文章中使用的例子可以通过以下链接查看

http://files.cnblogs.com/wilber2013/pipeline.js

MongoDB聚合管道的更多相关文章

  1. MongoDB 聚合(管道与表达式)

    MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*). aggregate() 方法 MongoDB中 ...

  2. MongoDB 聚合管道(Aggregation Pipeline)

    管道概念 POSIX多线程的使用方式中, 有一种很重要的方式-----流水线(亦称为"管道")方式,"数据元素"流串行地被一组线程按顺序执行.它的使用架构可参考 ...

  3. MongoDB聚合管道(Aggregation Pipeline)

    参考聚合管道简介 聚合管道 聚合管道是基于数据处理管道模型的数据聚合框架.文档进入一个拥有多阶段(multi-stage)的管道,并被管道转换成一个聚合结果.最基本的管道阶段提供了跟查询操作类似的过滤 ...

  4. MongoDB基础教程系列--第七篇 MongoDB 聚合管道

    在讲解聚合管道(Aggregation Pipeline)之前,我们先介绍一下 MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进行一系列操作,例如,求最 ...

  5. mongodb聚合管道用法

    基本用法 db.collection.aggregate( [ { <stage> }, ... ] ) stage如下 名称 描述 $addFields 将新的字段添加到文档中,输出的文 ...

  6. MongoDB 聚合管道

     参见:http://www.cnblogs.com/liruihuan/p/6686570.html MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进 ...

  7. MongoDB 聚合管道(aggregate)

    1.aggregate() 方法 我们先插入一些测试数据 { "_id" : ObjectId("5abc960c684781cda6d38027"), &qu ...

  8. 【翻译】MongoDB指南/聚合——聚合管道

    [原文地址]https://docs.mongodb.com/manual/ 聚合 聚合操作处理数据记录并返回计算后的结果.聚合操作将多个文档分组,并能对已分组的数据执行一系列操作而返回单一结果.Mo ...

  9. MongoDB学习笔记——聚合操作之聚合管道(Aggregation Pipeline)

    MongoDB聚合管道 使用聚合管道可以对集合中的文档进行变换和组合. 管道是由一个个功能节点组成的,这些节点用管道操作符来进行表示.聚合管道以一个集合中的所有文档作为开始,然后这些文档从一个操作节点 ...

随机推荐

  1. ES06--elasticsearch

    ES06--elasticsearch unassigned错误解决(手动处理)   查看集群健康状态:curl -XGET http://localhost:9200/_cluster/health ...

  2. PCL中分割方法的介绍(3)

    (3)上两篇介绍了关于欧几里德分割,条件分割,最小分割法等等还有之前就有用RANSAC法的分割方法,这一篇是关于区域生成的分割法, 区 域生长的基本 思想是: 将具有相似性的像素集合起来构成区域.首先 ...

  3. 微信小程序——自定义图标组件

    字体图标在网页中非常常见了.为了方便在小程序里面重复使用,自定义了一个图标组件,方便控制它的大小,颜色,自定义点击事件. 自定义图标组件的代码如下: 下面的代码是icon文件夹下面的4个文件 inde ...

  4. css实现三角形及应用示例

    css实现三角形,网上讲了很多,但我发现一般都是三角向上或者向下的,向左向右这两方向似乎讲得很少,本人试了一下,发现原来在IE下很难搞~~(万恶的IE)...css实现三角形的原理是:当元素的宽高为0 ...

  5. Linux gcc/g++链接编译顺序详解

    gcc/g++链接时对库的顺序要求 -Ldir Add directory dir to the list of directories to be searched for -l. -llibrar ...

  6. Linux中通过/proc/stat等文件计算Cpu使用率

    Linux平台Cpu使用率的计算 proc文件系统 /proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文件系统的方式为内核与进程提供通信的接口.用户和应用程序可以通过/pro ...

  7. 初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞

    这篇相当于是对前三篇的总结,基本效果如下: 在初试PyOpenGL一 (Python+OpenGL)讲解Pyopengl环境搭建,网格,球体,第一与第三人称摄像机的实现.在初试PyOpenGL二 (P ...

  8. qualcomm 查看 wifi 配置生效

    iwpriv wlan0 getConfig 然后收集dmesg, 或者执行这条命令: dmesg | grep gEnableBmps

  9. 关于eclipse导工程或移植工程常碰到的错误汇总

      在开发过程中,eclipse是使用得最多的IDE,但由于其开源且免费的性质决定了其不然有很多的BUG,在项目很赶的时期碰到某些很恶的错误很浪费时间,也很让人郁闷,现我总结一下我碰到的错误并总结下对 ...

  10. 性能优化系列三:JVM优化

    一.几个基本概念 GCRoots对象都有哪些 所有正在运行的线程的栈上的引用变量.所有的全局变量.所有ClassLoader... 1.System Class.2.JNI Local3.JNI Gl ...