【问题标题】:How to limit number of updating documents in mongodb如何限制MongoDB中更新文档的数量
【发布时间】:2020-06-18 04:27:40
【问题描述】:

如何在更新文档时实现类似于db.collection.find().limit(10) 的东西?

现在我正在使用一些非常糟糕的东西,比如使用 db.collection.find().limit() 获取文档然后更新它们。

一般来说,我想返回给定数量的记录并更改每个记录中的一个字段。

谢谢。

【问题讨论】:

  • 仅供参考:有一张票(自 2010 年起,v1.6.0)jira.mongodb.org/browse/SERVER-1599,但短期内不会发布。
  • 这张票现在已经修复了,但实际上并不是要对更新操作添加限制(仅涉及 $hint)

标签: mongodb


【解决方案1】:

你可以使用:

db.collection.find().limit(NUMBER_OF_ITEMS_YOU_WANT_TO_UPDATE).forEach(
    function (e) {
        e.fieldToChange = "blah";
        ....
        db.collection.save(e);
    }
);

(forEach 代码的学分:MongoDB: Updating documents using data from the same document

这只会更改您指定的条目数。因此,例如,如果您想在“集合”内的一半条目中添加一个名为“newField”且值为 1 的字段,例如,您可以放入

db.collection.find().limit(db.collection.count() / 2).forEach(
    function (e) {
        e.newField = 1;
        db.collection.save(e);
    }
);

如果你想让另一半也有“newField”但值为2,你可以在newField不存在的条件下进行更新:

db.collection.update( { newField : { $exists : false } }, { $set : { newField : 2 } }, {multi : true} );

【讨论】:

  • 这种情况下会有多少查询被发送到mongo服务器?是 1 表示查找,N 表示查找的 N 个结果吗?
  • 真的吗?没有人注意到这里的 N +1 db 调用问题?
【解决方案2】:

使用forEach 单独更新每个文档很慢。您可以使用

批量更新文档
ids = db.collection.find(<condition>).limit(<limit>).map(
    function(doc) {
        return doc._id;
    }
);
db.collection.updateMany({_id: {$in: ids}}, <update>})

【讨论】:

  • 如果你使用这种方法你应该在查询中添加一个投影来提高性能(你只需要_id):db.collection.find(, {_id: 1})
  • 当我尝试这个时它说:[ASYNC-10007] 无法将 Mongosh API 对象作为参数传递给函数
【解决方案3】:

遍历所有对象然后单独更新它们的解决方案非常慢。

检索它们然后使用$in 同时更新更有效。

ids = People.where(firstname: 'Pablo').limit(10000).only(:_id).to_a.map(&:id)
People.in(_id: ids).update_all(lastname: 'Cantero')

查询是使用 Mongoid 编写的,但也可以在 Mongo Shell 中轻松重写。

【讨论】:

    【解决方案4】:

    不幸的是,您拥有的解决方法是 AFAIK 的唯一方法。有一个布尔标志 multi 将更新所有匹配项(当 true 时)或更新第一个匹配项(当 false 时)。

    【讨论】:

      【解决方案5】:

      正如答案所述,仍然无法将要更新(或删除)的文档数量限制为 > 1。使用以下方法的解决方法:

      db.collection.find(<condition>).limit(<limit>).forEach(function(doc){db.collection.update({_id:doc._id},{<your update>})})
      

      【讨论】:

        【解决方案6】:

        如果您的 id 是序列号而不是 ObjectId,您可以在 for 循环中执行此操作:

        let batchSize= 10;
        for (let i = 0; i <= 1000000; i += batchSize) { 
          db.collection.update({$and :[{"_id": {$lte: i+batchSize}}, {"_id": {$gt: i}}]}),{<your update>})
        }
        

        【讨论】:

          猜你喜欢
          • 2022-10-17
          • 1970-01-01
          • 1970-01-01
          • 2017-07-04
          • 1970-01-01
          • 2016-06-17
          • 1970-01-01
          • 2017-08-15
          相关资源
          最近更新 更多