【问题标题】:MongoDB, conditional upserts or updatesMongoDB,条件更新或更新
【发布时间】:2017-08-03 10:38:45
【问题描述】:

当使用 MongoDB 时,我目前正在做一个条件 upsert 作为聚合过程的一部分,在表单上(很多简化):

db.dbname.update({attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1}},
                 false (multi), true (upsert))

但我也希望能够保留最大值(和最小值),而不必检索文档。大致如下:

db.dbname.update({ attr1 : value1, attr2 : value2},
                 {"$inc" : { avg : current_value, nr : 1},
                  "$setIfBigger" : { max : current_value}},
                 false (multi), true (upsert))

这是否可能以一种有效的方式实现?

我当前的、效率极低的解决方案是检查当前的聚合文档,如果存在,我相应地更新值,如果不存在,我创建一个新文档。示例(再次,简化了很多,但精髓就在那里):

var obj = db.dbname.findOne({attr1 : value1, attr2 : value2},{_id:1});
if (obj != null) {
   db.dbname.update({attr1 : value1, attr2 : value2},
                    {"$inc" : { avg : current_value, nr : 1},
                     "$set" : { max : (obj.max > current_value ? obj.max : current_value}},
                    false (multi), true (upsert));
} else {
   db.dbname.save({attr1 : value1, attr2 : value2, 
                   avg : current_value, nr : 1,
                   max : current_value});
}

实际的程序是用 Java 编写的,使用 mongo-API,聚合过程非常复杂,并且使用超越 Javascript 的组合技术与其他服务器通信,因此 mapreduce 不是一个选项。最后,最终结果是一组非常庞大的简单值,我想以最有效的方式存储它们,并存储某些组合的预先计算的平均值、最大值和最小值。

一种解决方案是在 JS 中为每次更新创建唯一的函数对象,我认为这不是一种有效的方法?

主要目标是减少执行此类聚合所需的时间,带宽使用是次要的。

【问题讨论】:

    标签: javascript mongodb database


    【解决方案1】:

    现在可以在包含Insert and Update Improvements 的 MongoDB 2.6 版本中更轻松地完成此操作。具体来说,有新的$min$max 运算符根据指定值的相对大小和字段的当前值执行条件更新。

    例如这次更新:

    db.scores.update( { _id: 1 }, { $max: { highScore: 950 } } )
    

    如果 950 大于 highScore 的当前值,将有条件地更新指定的文档。

    【讨论】:

      【解决方案2】:

      一种解决方案是在 JS 中为每次更新创建唯一的函数对象,我认为这不是一种有效的方法?

      可能无法如您所愿:

      https://jira.mongodb.org/browse/SERVER-458

      这是否可能以一种有效的方式实现?

      您面临的问题是您希望 MongoDB 使用更复杂的逻辑执行 upsert。因此,您希望利用文档级锁定来一次有效地“触发”多个复杂更改。

      你不是第一个想要这个的人,很遗憾它现在不可用。有几个与这种“更复杂的更新行为”相关的服务器错误。您可能想观看/投票以下几项以检查进度。

      $set only when insertingadd only when not existingpush and set at the same timecoordinate a "size" with $addToSet

      特别是,SERVER-458 似乎最接近你想要的。

      【讨论】:

      • 好吧,这意味着我无法提高性能然后 =( 感谢您的回答!SERVER-458 会解决问题,即使我相信 $setIfBigger 和 $setIfSmaller 会作为一个快速修复更容易。
      • 您绝对可以提出这些选项的请求 (jira.mongodb.org)。
      • 更改了正确答案,因为MongoDB 现在已经获得了所需的功能。我有点不确定这在 SO 道德方面是否正确..
      • @flindeberg 这是 15 分,我有 25k+ 和 600 多个答案,所以我会活下去:) 嘿,看起来这 4 个问题之一实际上是在过去 3 年多的时间里解决的。耶,蒙戈!
      猜你喜欢
      • 2016-08-10
      • 1970-01-01
      • 1970-01-01
      • 2016-11-15
      • 2013-10-16
      • 1970-01-01
      • 2017-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多