第六章 - 数据聚合

2018-02-24 16:17 更新

聚合管道(Aggregation Pipeline)

聚合管道提供了一种方法用于转换整合文档到集合。你可以通过管道来传递文档,就像 Unix 的 "pipe" 一样,将一个命令的输出传递到另第二个,第三个,等等。

最简单的聚合,应该是你在 SQL 中早已熟悉的 group by 操作。我们已经看过 count() 方法,那么假设我们怎么才能知道有多少匹公独角兽,有多少匹母独角兽呢?

db.unicorns.aggregate([{$group:{_id:'$gender',
    total: {$sum:1}}}])

在 shell 中,我们有 aggregate 辅助类,用来执行数组的管道操作。对于简单的对某物进行分组计数,我们只需要简单的调用 $group。这和 SQL 中的 GROUP BY 完全一致,我们用来创建一个新的文档,以 _id 字段表示我们以什么来分组(在这里是以 gender) ,另外的字段通常被分配为聚合的结果,在这里,我们对匹配某一性别的各文档使用了 $sum 1 。你应该注意到了 _id 字段被分配为 '$gender' 而不是 'gender' - 字段前面的 '$' 表示,该字段将会被输入的文档中的有同样名字的值所代替,一个占位符。

我们还可以用其他什么管道操作呢?在 $group 之前(之后也很常用)的一个是 $match - 这和 find 方法完全一样,允许我们获取文档中某个匹配的子集,或者在我们的结果中对文档进行筛选。

db.unicorns.aggregate([{$match: {weight:{$lt:600}}},
    {$group: {_id:'$gender',  total:{$sum:1},
      avgVamp:{$avg:'$vampires'}}},
    {$sort:{avgVamp:-1}} ])

这里我们介绍另外一个管道操作 $sort ,作用和你想的完全一致,还有和它一起用的 $skip 和 $limit。以及用$group 操作 $avg

MongoDB 数组非常强大,并且他们不会阻止我们往保存中的数组中写入内容。我们需要可以 "flatten" 他们以便对所有的东西进行计数:

db.unicorns.aggregate([{$unwind:'$loves'},
    {$group: {_id:'$loves',  total:{$sum:1},
    unicorns:{$addToSet:'$name'}}},
    {$sort:{total:-1}}, 
    {$limit:1} ])

这里我们可以找出独角兽最喜欢吃的食物,以及拿到独角兽们喜欢吃的食物名单。 $sort 和 $limit 的组合能让你拿到 "top N" 这种查询的结果。

还有另外一个强大的管道操作叫做 $project (类似于 find),不但允许你拿到指定字段,还可以根据现存字段进行创建或计算一个新字段。比如,可以用数学操作,在做平均运算之前,对几个字段进行加法运算,或者你可以用字符串操作创建一个新的字段,用于拼接现有字段。

这只是用聚合所能做到的众多功能中的皮毛, 2.6 的聚合拥有了更强大的力量,比如聚合命令可以返回结果集的游标(我们已经在第一章学过了) 或者可以将结果写到另外一个新集合中,通过 $out 管道操作。你可以从 MongoDB 手册 得到关于管道操作和表达式操作更多的例子。

MapReduce

MapReduce 分两步进行数据处理。首先是 map,然后 reduce。在 map 步骤中,转换输入文档和输出一个 key=>value 对(key 和/或 value 可以很复杂)。然后, key/value 对以 key 进行分组,有同样的 key 的 value 会被收入一个数组中。在 reduce 步骤中,获取 key 和该 key 的 value 的数组,生成最终结果。map 和 reduce 方法用 JavaScript 来编写。

在 MongoDB 中我们对一个集合使用 mapReduce 命令。 mapReduce 执行 map 方法, reduce 方法和 output 指令。在我们的 shell 中,我们可以创建输入一个 JavaScript 方法。许多库中,支持字符串方法 (有点丑)。第三个参数设置一个附加参数,比如说我们可以过滤,排序和限制那些我们想要分析的文档。我们也可以提供一个 finalize 方法来处理 reduce 步骤之后的结果。

在你的大多数聚合中,也许无需用到 MapReduce , 但如果需要,你可以读到更多关于它的内容,从 我的 blog 和 MongoDB 手册

小结

在这章中我们介绍了 MongoDB 的 聚合功能(aggregation capabilities)。 一旦你理解了聚合管道(Aggregation Pipeline)的构造,它还是相对容易编写的,并且它是一个聚合数据的强有力工具。 MapReduce 更难理解一点,不过它强力无边,就像你用 JavaScript 写的代码一样。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号