【问题标题】:How to sum the value of a key across all documents in a MongoDB collection如何对 MongoDB 集合中所有文档的键值求和
【发布时间】: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 }

【问题讨论】:

    标签: mongodb nosql


    【解决方案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'
        }
    })
    
    1. 使用 $group 和 $sum 来计算总和
    2. 使用投影的 $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 }])``
    猜你喜欢
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    • 2022-12-08
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    相关资源
    最近更新 更多