就我个人而言,我的文档中不会有一个对象,而是一个数组。它本身并不能解决不覆盖数据的问题,但它确实将“键”上的“查找”变成了使用可以索引的“数据”。如果您打算定期进行此类更新,这将产生“重大”影响。
{
"name": "Doc1",
"properties": [
{ "key": "a", "value": 123 },
{ "key": "b", "value": 456 }
]
}
因此对于“b”和“c”的新数据,您可以进行如下查询尝试:
db.collection.update(
{ "properties.key" { "$nin": [ "b", "c" ] } },
{
"$push": {
"properties": {
"$each": [
{ "key": "b", "value": 789 },
{ "key": "c", "value": 101 }
]
}
}
},
{ "multi": true }
)
如前所述,至少“可以”使用$exists 的“键”查找不能使用的索引,并且您至少可以“尝试”将此操作作为“第一枪”执行,如果文档确实如此满足“b”和“c”,“key”值都不存在的给定条件,那么这些文档将受到影响。
后备案例当然是对这里的每个属性单独尝试,但整个过程真的不难用Bulk Operations解决:
var obj = { "b": 456, "c": 101 };
var keys = Object.keys(obj),
mapped = keys.map(function(key) {
return { "key": key, "value": obj[key] };
});
var bulk = intitializeOrderedBulkOp();
bulk.find({ "properties.key": { "$nin": keys } }).update({
"$push": { "properties": { "$each": mapped } }
});
keys.forEach(function(key) {
bulk.find({ "properties.key": { "$ne": key } }).update({
"$push": { "properties": { "key": key, "value": obj[key] } }
});
});
bulk.execute();
请注意,如果第一个查询确实成功了,那么其他一切都可能是“无操作”。但是,如果您像这样使用“multi”来执行此操作,那么除非您已经知道要测试多少个文档,否则您永远无法确定。所以可能一次性发送是“比抱歉更安全”。
所以它很容易编码,由于批量操作而往返于服务器一次,并且由于能够使用索引而在查找数据以匹配条件时“高效”。
您要实现的“放弃合并”逻辑总是意味着多次更新。但是,如果您至少使流程尽可能“高效”,那么至少可以少担心一件事。