更新加入 mongoDB。是否可以?

str*_*ttn 4 mongodb

鉴于这三个文件:

db.test.save({"_id":1, "foo":"bar1", "xKey": "xVal1"});
db.test.save({"_id":2, "foo":"bar2", "xKey": "xVal2"});
db.test.save({"_id":3, "foo":"bar3", "xKey": "xVal3"});
Run Code Online (Sandbox Code Playgroud)

以及引用这些文档的单独信息数组:

[{"_id":1, "foo":"bar1Upd"},{"_id":2, "foo":"bar2Upd"}]
Run Code Online (Sandbox Code Playgroud)

是否可以在一次操作中更新两个引用文档(1 和 2)上的“foo”?

我知道我可以遍历数组并一个一个地执行它们,但是我有数千个文档,这意味着到服务器的往返次数太多。

非常感谢您的想法。

chr*_*dam 6

不可能在单个原子操作中更新两个引用文档(1 和 2)上的“foo”,因为 MongoDB 没有这种机制。但是,看到您有一个大集合,一种选择是利用Bulk API允许您批量发送更新而不是每个更新请求到服务器。

该过程涉及循环数组中的所有匹配文档并处理批量更新,这至少允许在具有单一响应的单个请求中发送许多操作。

这为您提供了更好的性能,因为您不会将每个请求发送到服务器,而是每 500 个请求发送一次,从而使您的更新更高效、更快捷。

-编辑-

选择较低值的原因通常是受控选择。正如那里的文档中所述,默认情况下,MongoDB 将最多一次以 1000 个操作的批次发送到服务器,并且不能保证确保这些默认的 1000 个操作请求实际上符合16MB BSON 限制。因此,您仍然需要站在“安全”的一边,并强加您只能有效管理的较低批量大小,以便在发送到服务器时它的总数小于数据大小限制。


让我们用一个例子来演示上面的方法:

a)如果使用 MongoDB v3.0 或更低版本:

var bulk = db.test.initializeOrderedBulkOp(),
    largeArray = [{"_id":1, "foo":"bar1Upd"},{"_id":2, "foo":"bar2Upd"}],
    counter = 0;

largeArray.forEach(doc) {    
    bulk.find({ "_id": doc._id }).updateOne({ "$set": { "foo": doc.foo } });
    counter++;

    if (counter % 500 == 0) {
        bulk.execute();
        bulk = db.test.initializeOrderedBulkOp();
    }
} 

if (counter % 500 != 0 ) bulk.execute();
Run Code Online (Sandbox Code Playgroud)

b)如果使用 MongoDB v3.2.X 或更高版本(新的 MongoDB 3.2 版已弃用Bulk()API 并使用 提供了一组较新的 api bulkWrite()):

var largeArray = [{"_id":1, "foo":"bar1Upd"},{"_id":2, "foo":"bar2Upd"}],
    bulkUpdateOps = [];

largeArray.forEach(function(doc){     
    bulkUpdateOps.push({ 
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": { "$set": { "foo": doc.foo } }
        }
    });

    if (bulkUpdateOps.length === 500) {
        db.test.bulkWrite(bulkUpdateOps);
        bulkUpdateOps = [];
    }
});         

if (bulkUpdateOps.length > 0) db.test.bulkWrite(bulkUpdateOps); 
Run Code Online (Sandbox Code Playgroud)