MongoDB中聚合工具Aggregate等的介绍与使用
Aggregate是MongoDB提供的众多工具中的比较重要的一个,类似于SQL语句中的GROUP BY。聚合工具可以让开发人员直接使用MongoDB原生的命令操作数据库中的数据,并且按照要求进行聚合。
MongoDB提供了三种执行聚合的方法:Aggregation Pipleline,map-reduce功能和 Single Purpose Aggregation Operations
其中用来做聚合操作的几个函数是
aggregate(pipeline,options)指定 group 的 keys, 通过操作符$push/$addToSet/$sum等实现简单的 reduce, 不支持函数/自定义变量group({ key, reduce, initial [, keyf] [, cond] [, finalize] })支持函数(keyf)mapReduce的阉割版本mapReducecount(query)distinct(field,query)
1、Aggregation Pipleline
MongoDB’s aggregation framework is modeled on the concept of data processing pipelines. Documents enter a multi-stage pipeline that transforms the documents into an aggregated result.
管道在*nix中将上一个命令输出的数据作为下一个命令的参数。MongoDB中的管道聚合非常实用,提供高效的数据聚合,并且是MongoDB中数据聚合的首选方法
官方给的图:

[
{$match: {status: "A"}},
{$group: {_id: "$cust_id", total: {$sum: "$amount"}}}
]
aggreagte是一个数组,其中包含多个对象(命令),通过遍历Pipleline数组对collection中的数据进行操作。
$match:查询条件
$group:聚合的配置
_id代表你想聚合的数据的主键,上述数据中,你想聚合所有cust_id相同的条目的amount的总和,那_id即被设置为cust_id。_id为必须,你可以填写一个空值。total代表你最后想输出的数据之一,这里total是每条结果中amount的总和。$sum是一个聚合的操作符,另外的操作符你可以在官方文档中找到。上图中的命令表示对相同主键(_id)下的amount进行求和。如果你想要计算主键出现的次数,可以把命令写成如下的形式{$sum: 1}
聚合的过程
看一下图例,所有的数据先经过$match命令,只留下了status为A的数据,接着,对筛选出的数据进行聚合操作,对相同cust_id的数据进行计算amount总和的操作,最后输出结果。
二、aggregate具体介绍
接受两个参数 pipeline/options, pipeline 是 array, 相同的 operator 可以多次使用
pipeline 支持的方法
$geoNeargeoNear命令可以在查询结果中返回每个点距离查询点的距离$group指定 group 的_id(key/keys) 和基于操作符($push/$sum/$addToSet/...) 的累加运算$limit限制条件$match输入过滤条件$out将输出结果保存到collection$project修改数据流中的文档结构$redact是$project/$match功能的合并$skip 跳过$sort对结果排序$unwind拆解数据
$group 允许用的累加操作符 $addToSet/$avg/$first/$last/$max/$min/$push/$sum,不被允许的累加操作符$each... ,默认最多可以用 100MB RAM, 增加allowDiskUse可以让$group操作更多的数据
下面是aggregate的用法
db.newtest.aggregate([
{$match: {}},
{$skip: 10}, // 跳过 collection 的前 10 行
{$project: {group: 1, datetime: 1, category: 1, count: 1}},
// 如果不选择 {count: 1} 最后的结果中 count_all/count_avg = 0
{$redact: { // redact 简单用法 过滤 group != 'A' 的行
$cond: [{$eq: ["$group", "A"]}, "$$DESCEND", "$$PRUNE"]
}},
{$group: {
_id: {year: {$year: "$datetime"}, month: {$month: "$datetime"}, day: {$dayOfMonth: "$datetime"}},
group_unique: {$addToSet: "$group"},
category_first: {$first: "$category"},
category_last: {$last: "$category"},
count_all: {$sum: "$count"},
count_avg: {$avg: "$count"},
rows: {$sum: 1}
}},
// 拆分 group_unique 如果开启这个选项, 会导致 _id 重复而无法写入 out 指定的 collection, 除非再 $group 一次
// {$unwind: "$group_unique"},
// 只保留这两个字段
{$project: {group_unique: 1, rows: 1}},
// 结果按照 _id 排序
{$sort: {"_id": 1}},
// 只保留 50 条结果
// {$limit: 50},
// 结果另存
{$out: "data_agg_out"},
], {
explain: true,
allowDiskUse: true,
cursor: {batchSize: 0}
})
db.data_agg_out.find()
db.data_agg_out.aggregate([
{$group: {
_id: null,
rows: {$sum: '$rows'}
}}
])
db.data_agg_out.drop()
$match聚合前数据筛选$skip跳过聚合前数据集的 n 行, 如果{$skip: 10}, 最后rows = 5000000 - 10$project之选择需要的字段, 除了_id之外其他的字段的值只能为 1$redact看了文档不明其实际使用场景, 这里只是简单筛选聚合前的数据$group指定各字段的累加方法$unwind拆分 array 字段的值, 这样会导致_id重复$project可重复使用多次 最后用来过滤想要存储的字段$out如果$group/$project/$redact的_id没有重复就不会报错以上方法中
$project/$redact/$group/$unwind可以使用多次
二、group
group 比 aggregate 好的一个地方是 map/reduce 都支持用 function 定义, 下面是支持的选项
ns如果用db.runCommand({group: {}})方式调用, 需要ns指定 collectioncond聚合前筛选key聚合的 keyinitial初始化 累加 结果$reduce接受(curr, result)参数, 将curr累加到resultkeyf代替key用函数生成聚合用的主键finalize结果处理
需要保证输出结果小于 16MB 因为 group 没有提供转存选项
db.data.group({
cond: {'group': 'A'},
// key: {'group': 1, 'category': 1},
keyf: function(doc) {
var dt = new Date(doc.created);
// or
// var dt = doc.datetime;
return {
year: doc.datetime.getFullYear(),
month: doc.datetime.getMonth() + 1,
day: doc.datetime.getDate()
}
},
initial: {count: 0, category: []},
$reduce: function(curr, result) {
result.count += curr.count;
if (result.category.indexOf(curr.category) == -1) {
result.category.push(curr.category);
}
},
finalize: function(result) {
result.category = result.category.join();
}
})
如果要求聚合大量数据, 就需要用到 mapReduce
三、mapReduce
query聚合前筛选sort对聚合前的数据排序 用来优化 reducelimit限制进入 map 的数据map(function) emit(key, value) 在函数中指定聚合的 K/Vreduce(function) 参数(key, values)key在 map 中定义了,values是在这个 K 下的所有 V 数组finalize处理最后结果out结果转存 可以选择另外一个 dbscope设置全局变量jdMode(false) 是否(默认是)把 map/reduce 中间结果转为 BSON 格式, BSON 格式可以利用磁盘空间, 这样就可以处理大规模的数据集verbose(true) 详细信息
如果设 jsMode 为 true 不进行 BSON 转换, 可以优化 reduce 的执行速度, 但是由于内存限制最大在 emit 数量小于 500,000 时使用
写 mapReduce 时需要注意
- emit 返回的 value 必须和 reduce 返回的 value 结构一致
reduce函数必须幂等- 详见 Troubleshoot the Reduce Function
db.data.mapReduce(function() {
var d = this.datetime;
var key = {
year: d.getFullYear(),
month: d.getMonth() + 1,
day: d.getDate(),
};
var value = {
count: this.count,
rows: 1,
groups: [this.group],
}
emit(key, value);
}, function(key, vals) {
var reducedVal = {
count: 0,
groups: [],
rows: 0,
};
for(var i = 0; i < vals.length; i++) {
var v = vals[i];
reducedVal.count += v.count;
reducedVal.rows += v.rows;
for(var j = 0; j < v.groups.length; j ++) {
if (reducedVal.groups.indexOf(v.groups[j]) == -1) {
reducedVal.groups.push(v.groups[j]);
}
}
}
return reducedVal;
}, {
query: {},
sort: {datetime: 1}, // 需要索引 否则结果返回空
limit: 50000,
finalize: function(key, reducedVal) {
reducedVal.avg = reducedVal.count / reducedVal.rows;
return reducedVal;
},
out: {
inline: 1,
// replace: "",
// merge: "",
// reduce: "",
},
scope: {},
jsMode: true
})
测试数据:
> db.newtest.find()
{ "_id" : ObjectId("5a2544352ba57ccba824d7bf"), "group" : "E", "created" : 1402764223, "count" : 63, "datetime" : 1512391126, "title" : "aa", "category" : "C8" }
{ "_id" : ObjectId("5a2544512ba57ccba824d7c0"), "group" : "I", "created" : 1413086660, "count" : 93, "datetime" : 1512391261, "title" : "bb", "category" : "C10" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c1"), "group" : "H", "created" : 1440750343, "count" : 41, "datetime" : 1512391111, "title" : "cc", "category" : "C1" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c2"), "group" : "S", "created" : 1437710373, "count" : 14, "datetime" : 1512392136, "title" : "dd", "category" : "C10" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c3"), "group" : "Z", "created" : 1428307315, "count" : 78, "datetime" : 1512391166, "title" : "ee", "category" : "C5" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c4"), "group" : "R", "created" : 1402809274, "count" : 74, "datetime" : 1512391162, "title" : "ff", "category" : "C9" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c5"), "group" : "Y", "created" : 1400571321, "count" : 66, "datetime" : 1512139164, "title" : "gg", "category" : "C2" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c6"), "group" : "L", "created" : 1416562128, "count" : 5, "datetime" : 1512393165, "title" : "hh", "category" : "C1" }
{ "_id" : ObjectId("5a2544562ba57ccba824d7c7"), "group" : "E", "created" : 1414057884, "count" : 12, "datetime" : 1512391165, "title" : "ii", "category" : "C3" }
{ "_id" : ObjectId("5a2544572ba57ccba824d7c8"), "group" : "L", "created" : 1418879346, "count" : 67, "datetime" : 1512391167, "title" : "gg", "category" : "C3" }
四、总结
| method | allowDiskUse | out | function |
|---|---|---|---|
| aggregate | true | pipeline/collection | false |
| group | false | pipeline | true |
| mapReduce | jsMode | pipeline/collection | true |
aggregate基于累加操作的的聚合 可以重复利用$project/$group一层一层聚合数据, 可以用于大量数据(单输出结果小于 16MB) 不可用于分片数据mapReduce可以处理超大数据集 需要严格遵守 mapReduce 中的结构一致/幂等 写法, 可增量输出/合并, 见outoptionsgroupRDB 中的group by简单需求可用(只有 inline 输出) 会产生read lock
MongoDB中聚合工具Aggregate等的介绍与使用的更多相关文章
- MongoDB中的数据聚合工具Aggregate和Group
周煦辰 2016-01-16 来说说MongoDB中的数据聚合工具. Aggregate是MongoDB提供的众多工具中的比较重要的一个,类似于SQL语句中的GROUP BY.聚合工具可以让开发人员直 ...
- MongoDB的聚合函数 Aggregate
Aggregate的使用,有利于我们对MongoDB中的集合进行进一步的拆分. 示例: db.collection.aggregate( {$match:{x:1}, {limit:10}, {$gr ...
- MongoDB中4种日志的详细介绍
前言 任何一种数据库都有各种各样的日志,MongoDB也不例外.MongoDB中有4种日志,分别是系统日志.Journal日志.oplog主从日志.慢查询日志等.这些日志记录着MongoDB数据库不同 ...
- MongoDB 中聚合统计计算--$SUM表达式
我们一般通过表达式$sum来计算总和.因为MongoDB的文档有数组字段,所以可以简单的将计算总和分成两种:1,统计符合条件的所有文档的某个字段的总和:2,统计每个文档的数组字段里面的各个数据值的和. ...
- 【翻译】MongoDB指南/聚合——聚合管道
[原文地址]https://docs.mongodb.com/manual/ 聚合 聚合操作处理数据记录并返回计算后的结果.聚合操作将多个文档分组,并能对已分组的数据执行一系列操作而返回单一结果.Mo ...
- 在MongoDB中执行查询、创建索引
1. MongoDB中数据查询的方法 (1)find函数的使用: (2)条件操作符: (3)distinct找出给定键所有不同的值: (4)group分组: (5)游标: (6)存储过程. 文档查找 ...
- MongoDB的聚合操作以及与Python的交互
上一篇主要介绍了MongoDB的基本操作,包括创建.插入.保存.更新和查询等,链接为MongoDB基本操作. 在本文中主要介绍MongoDB的聚合以及与Python的交互. MongoDB聚合 什么是 ...
- MongoDB入门---聚合操作&管道操作符&索引的使用
经过前段时间的学习呢,我们对MongoDB有了一个大概的了解,接下来就要开始使用稍稍深入一点的东西了,首先呢,就是MongoDB中的聚合函数,跟mysql中的count等函数差不多.话不多说哈,我们先 ...
- Mongodb的聚合和管道
MongoDB 聚合 MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果. aggregate() 方法 MongoDB中聚合的方法使用agg ...
随机推荐
- 【NOIP2016提高组】 Day2 T2 蚯蚓
题目传送门:https://www.luogu.org/problemnew/show/P2827 自测时被题面所误导...,题面中说逢t的倍数才输出答案,以为有什么玄妙的方法直接将m次操作变成了m/ ...
- Zookeeper 笔记-应用场景
应用场景:数据发布,订阅:分布式应用配置项:分布式计数器:统一命名服务:状态同步服务:集群管理:Master选举:分布式锁:定时任务争夺:分布式队列:分布式协调通知 特点:顺序一致性,原子性,单一视图 ...
- HttpComponents 发送post get 请求
1.场景描述 使用Apache开源组织中的HttpComponents,完成对http服务器的访问功能. 2.HttpComponents项目的介绍 HttpComponents项目就是专门设计来简化 ...
- C++运算符重载(10)
编译器在默认情况下为每个类生成一个默认的赋值操作,用于同类的两个对象之间相互赋值.默认的含义是逐个为成员赋值,即将一个对象的成员的值赋给另一个对象相应的成员,这种赋值方式对于有些类可能是不正确的. 运 ...
- [http服务]
[http服务] CentOS 6 httpd 程序环境 记录了httpd的主进程编号: v 主程序文件: /usr/sbin/httpd /usr/sbin/httpd.worker /usr/sb ...
- ubuntu中python3.4安装pip
这两天碰到在ubuntu中安装pip的问题. 第一种方法 用百度搜索了一下,基本上都是这个命令: sudo apt-get install python3-pip 但是,用这条命令下载速度特别慢. 第 ...
- 关于git常见的一些问题
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 Mark一下,最近用的比较少,担心忘记了. 作为一个程序员,git或者SVN是必备技能,尤其是 ...
- sublime text3 开发必备插件
1,Package Control 通俗易懂地说,这个是你在完成安装SublimeText后必须安装的东西.你问为什么?因为有了这个特殊的"插件包",你可以很容易地安装.升级.删除 ...
- HDU1175 连连看(DFS)
Problem Description “连连看”相信很多人都玩过.没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子.如果某两个相同的棋子,可以通过一条线连起来(这条线不能经 ...
- HDU 6113 度度熊的01世界
度度熊的01世界 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...