拥有以下名为eshops的集合:
{
"_id" : ObjectId("53e87e239ae974e6a0a81004"),
"name" : "www.example.com",
"products" : [
{
"name" : "apple", //lets say the name key here is primary key of products
"status" : 0
},
{
"name" : "banana",
"status" : 0
},
{
"name" : "iphone",
"status" : 0
}
]
}
并拥有此数组
var products = [
{name: "apple", status: 1}
{name: "notebook", status: 0}
]
如果我想要以下结果,更新查询应该是什么样的?
{
"_id" : ObjectId("53e87e239ae974e6a0a81004"),
"name" : "www.example.com",
"products" : [
{
"name" : "apple",
"status" : 1
},
{
"name" : "banana",
"status" : 0
},
{
"name" : "iphone",
"status" : 0
},
{
"name" : "notebook",
"status" : 0
}
]
}
答案 0 :(得分:1)
对此的全面解释是在最后阅读。
那不可能不能在一次操作中“原子地”完成,你将得到的最好的是"Bulk"操作,这是最好的方法。
var products = [
{name: "apple", status: 1}
{name: "notebook", status: 0}
];
var bulk = db.collection.initializeOrderedBulkOp();
products.forEach(function(product) {
// Try to update
bulk.find({
"_id" : ObjectId("53e87e239ae974e6a0a81004"),
"products.name": product.name
})
.updateOne({
"$set": { "products.$.status": product.status }
});
// Try to "push"
bulk.find({
"_id" : ObjectId("53e87e239ae974e6a0a81004"),
"products.name": { "$ne": product.name }
})
.updateOne({
"$push": { "products": product }
});
});
bulk.execute();
另一种方法是通过.findOne()
或类似操作检索文档,然后更改客户端代码中的数组内容,然后.save()
更改内容。
这是你不想要的,因为无法保证文档没有被“更改”,因为它被读入内存。如果其他成员被添加到数组中,那么某种操作会“覆盖”它们。
因此,循环使用多个更新的项目。至少“批量”操作会立即将这些操作发送到服务器,而无需等待单个写入的响应。
但正如你指出的那样。如果价值仍然相同怎么办?为此,您需要查看.execute()
上“批量”操作的“WriteResult”响应:
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
因此,这里有两(2)个动作,总共发送四(4)个操作。如果数组包含一个项目,说“iphone”没有更改:
var products = [
{name: "apple", status: 1}
{name: "notebook", status: 0},
{name: "iphone", status: 0 }
];
然后回复就是这样:
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 2 })
由于“Bulk”API非常智能,可以看到匹配的“iphone”上的“status”值与已经存在的值没有区别(假设之间没有其他任何改变)并且不会将此报告为修改。
所以让服务器完成工作,因为你可以编写的所有智能都已经存在了。