鉴于这三个文件:
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"});
引用这些文档的单独信息数组:
[{"_id":1, "foo":"bar1Upd"},{"_id":2, "foo":"bar2Upd"}]
是否可以在一次操作中更新两个引用文档(1和2)上的“foo”?
我知道我可以遍历数组并逐个执行,但是我有数千个文档,这意味着往返服务器的次数过多。
非常感谢你的想法。
答案 0 :(得分:3)
无法更新" foo"在单个原子操作中的两个引用文档(1和2)上,因为MongoDB没有这样的机制。但是,看到您有一个大型集合,一个选项是利用 Bulk API
,它允许您批量发送更新而不是每次更新请求到服务器。
该过程涉及循环数组中所有匹配的文档并处理批量更新,这将至少允许在单个请求中使用单一响应发送许多操作。
这为您提供了更好的性能,因为您不会将每个请求发送到服务器,而是每500个请求中只发送一次,从而使您的更新更加高效和快捷。
- 的 修改 强> -
选择较低值的原因通常是受控制的选择。正如那里的文档所述,默认情况下MongoDB将发送到server in batches of 1000 operations at a time at maximum,并且无法保证确保这些默认的1000个操作请求实际适合16MB BSON limit。所以你仍然需要在" safe"并且施加较小的批量大小,您只能有效地管理它,以便在发送到服务器时总数小于数据限制。
让我们用一个例子来演示上述方法:
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();
b)如果使用MongoDB v3.2.X或更高版本(新的MongoDB版本3.2已经deprecated Bulk()
API,使用 bulkWrite()
)提供了一套更新的apis:
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);