如何对 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 &lt;mycollection&gt;:

res = db.<mycollection>.mapReduce(map, red);

这将创建一个临时的新集合,您可以像任何其他集合一样操作。 mapReduce 返回的值包含有关 mapReduce 的多个值,例如所用时间、状态...以及温度。在“结果”字段中创建的集合名称。 要获取您需要的值,您必须查询该集合:

db[res.result].find()

应该给你对象&lt;key&gt;: &lt;sum&gt;

如果您运行 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 集合中所有文档的键值求和的主要内容,如果未能解决你的问题,请参考以下文章

如何对 MongoDB 集合中字段的不同值求和(利用 mongoose)

如何在键具有数组的多维数组中求和所有相同的键值?

如何对firebase firestore中的节点求和?

mongodb如何删除集合中的指定键值对???

从 JavaScript 中的键值对数组中求和值

MongoDB常用操作--集合2