强制限制MongoDB批量API的数量

5

我希望从一个集合中删除大量旧文档,因此使用批量API是有意义的。删除它们很简单:

var bulk = db.myCollection.initializeUnorderedBulkOp();

bulk.find({
  _id: {
    $lt: oldestAllowedId
  }
}).remove();

bulk.execute();

唯一的问题是,这将尝试删除与此条件匹配的每个文档,在这种情况下可能有数百万个文档,因此出于性能原因,我不想一次性将它们全部删除。我希望对操作进行限制,以便我可以执行类似于bulk.limit(10000).execute();的操作,并将操作间隔几秒钟,以防止数据库锁定时间过长。然而,我无法找到可以传递给批量操作以限制其执行数量的选项。
有没有一种方法可以以这种方式限制批量操作?
在任何人提到之前,我知道bulk会自动将操作拆分为1000个文档块,但它仍会按尽可能快的顺序执行所有这些操作。这导致的性能影响比我现在处理的要大得多。

为什么不直接使用(在shell中) db.collection.remove({"_id":{$lt:oldestIdAllowed}})呢? - Markus W Mahlberg
你是否尝试过像对待普通查询/游标一样使用 bulk.find({...}).limit(10000).remove(); 呢? - metame
算了,我刚试了一下,对于批量操作不起作用。 - metame
1
马库斯,我完全可以使用.remove(),这就是我这次要做的事情,但我想知道是否有可能强制限制批量操作以获得更好的批量操作性能。 - Rob Riddle
1个回答

2
您可以使用.forEach方法迭代与您的查询匹配的文档的_id数组。最好的返回该数组的方法是使用.distinct()方法。然后,您可以使用“bulk”操作来删除文档。
var bulk = db.myCollection.initializeUnorderedBulkOp();
var count = 0;

var ids = db.myCollection.distinct('_id', { '_id': { '$lt': oldestAllowedId } } );

ids.forEach(function(id) {
    bulk.find( { '_id': id } ).removeOne();
    count++;
    if (count % 1000 === 0) {
        // Execute per 1000 operations and re-init
        bulk.execute();
        // Here you can sleep for a while 
        bulk = db.myCollection.initializeUnorderedBulkOp();
    }
});

// clean up queues
if (count > 0 ) {
    bulk.execute();
}

这是可能的,但实际上更有效的方法是使用 var ids = db.collection.find(query, {_id:1}) 然后 bulk.find({$in: ids}).remove(),但我只是好奇是否可以在一个批量操作中完成所有这些。 - Rob Riddle
1
@RobRiddle 不行!这是因为使用Bulk API无法限制文档数量。此外,您应该使用distinct返回_id数组,因为_id是唯一的。 - styvane
1
由于 _id 是Mongo的默认唯一索引,因此 find 永远不会返回重复的 _id 结果,因此该查询不需要使用Mongo distinct 提供的任何额外逻辑。 如果是其他字段,则可能需要使用 distinct - Rob Riddle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接