如何对 MongoDB 集合中所有文档的键值求和
Posted
技术标签:
【中文标题】如何对 MongoDB 集合中所有文档的键值求和【英文标题】:How to sum the value of a key across all documents in a MongoDB collection 【发布时间】:2011-06-05 00:17:18 【问题描述】:我在 MongoDB 中有收藏:
"_id" : ObjectId("4d2407265ff08824e3000001"), "subida" : 3.95
"_id" : ObjectId("4d2551b4ae9fa739640df821"), "subida" : 6.03
"_id" : ObjectId("4d255b115ff08821c2000001"), "subida" : 5.53
"_id" : ObjectId("4d25e8d55ff08814f8000001"), "subida" : 1.96
如何对所有文档中的键值求和,例如 "subida"
?有了上述文件,我应该会收到以下内容:
"subida" : 17.47
【问题讨论】:
【参考方案1】:选项 0:使用MongoDB aggregation pipeline [注意:这个选项是在提出这个问题后很长时间才添加的,但现在是正确的方法]
选项 1:查询所有记录,仅从 Mongo 返回 subida 字段,并通过迭代 Mongo 游标客户端将它们相加。
选项 2:编写一个 map reduce 命令,只发出 subdia 字段(所有的 key 相同),然后编写一个 reduce 命令来汇总它们。
选项3:使用db.eval在服务器上执行javascript:http://www.mongodb.org/display/DOCS/Server-side+Code+Execution
选项 4:在将值插入集合时累积“subida”值,以便在需要时随时掌握最新的总计。您可以将总数存储在不同的文档中,并使用原子的“如果当前更新”操作来更新它:http://www.mongodb.org/display/DOCS/Atomic+Operations
【讨论】:
有什么例子比较生动易懂?【参考方案2】:您可以将集合用作数组,只需在循环中添加值即可。
编辑:是的,在拥有大数据集时这是一种不好的做法。
【讨论】:
大型日期集的错误做法【参考方案3】:我会亲自对集合执行 mapreduce:
map 是一个发出“subida”字段的简单函数。如果您需要一个总和,则密钥应该相同; reduce 之后的结果将产生单个对象 <key>: <sum>
,<key>
是您在发射中提供的任何值。
map = function() emit(<key>, this.subida);
reduce 也是一个简单的函数:
red = function(k, v)
var i, sum = 0;
for (i in v)
sum += v[i];
return sum;
然后你可以在你的集合上调用 mapreduce <mycollection>
:
res = db.<mycollection>.mapReduce(map, red);
这将创建一个临时的新集合,您可以像任何其他集合一样操作。 mapReduce 返回的值包含有关 mapReduce 的多个值,例如所用时间、状态...以及温度。在“结果”字段中创建的集合名称。 要获取您需要的值,您必须查询该集合:
db[res.result].find()
应该给你对象<key>: <sum>
。
如果您运行 MongoDB 1.7.4 或更高版本,您可以通过让 MongoDB 直接返回结果而不创建集合来为您省去一些麻烦:
db.<mycollection>.mapReduce(map, red, out : inline: 1);
【讨论】:
非常感谢朋友,我终于可以做这个查询了,在 mongo shell 中完美运行。我在我的应用程序中用 python 实现...我现在看到 mongodb map/reduce 查询不等于 CouchDB map/reduce 查询...大声笑:D 只是对为什么选择 mapreduce 而不是聚合感兴趣?【参考方案4】:在这种情况下,聚合比 mapReduce 更简单、更高效:
db.collection.aggregate(
$group:
_id: '',
subida: $sum: '$subida'
,
$project:
_id: 0,
subida: '$subida'
)
-
使用 $group 和 $sum 来计算总和
使用投影的 $project 运算符删除 $group 运算符所需的 id 键
【讨论】:
这种方法比当前的 Map/Reduce 实现要高效得多 +1 出色的答案。我在使用 "$sum": "subida":1 时出错了 欺骗 Spring DB 还不支持聚合框架:( @rdrkt - 您对此解决方案更快的测试/证据是什么? MapReduce 引擎是一个单线程的 javascript。它也不使用任何索引。聚合框架是多线程的原生 c++ 并尽可能使用索引。【参考方案5】:使用这个最简单的查询得到结果的总和
db.collection.aggregate(
$group:
_id: '',
subida: $sum: '$subida'
)
【讨论】:
不适用于猫鼬server error MongooseError: Mongoose 5.x disallows passing a spread of operators to
Model.aggregate(). Instead of
Model.aggregate( $match , $skip ), do
Model.aggregate([ $match , $skip ])``以上是关于如何对 MongoDB 集合中所有文档的键值求和的主要内容,如果未能解决你的问题,请参考以下文章