恐怕单个原子更新是不可能的,您必须执行几次满足这两个条件的更新操作。
将更新逻辑分解为两个不同的更新操作,第一个需要使用位置性的$操作员来识别其中的元素history
你想要的数组和$set更新现有字段。这个操作遵循以下逻辑如果名称和组织匹配,则更新字段
现在,您想要使用findAndModify()方法,因为它可以返回更新的文档。默认情况下,返回的文档不包含更新时所做的修改。
因此,有了这个武器库,您就可以在下一个操作中探测您的第二个逻辑,即如果数组中不存在“history.name”和“history.organization”的组合,则更新。有了这第二
更新操作,您需要使用$push运算符来添加元素。
以下示例演示了上述概念。它最初假设您将查询部分和文档作为单独的对象进行更新。
举个例子,当我们有与现有历史数组匹配的文档时,它只会执行一次更新操作,但如果文档不匹配,那么findAndModify()方法将返回 null,在第二个更新操作中使用此逻辑将文档推送到数组:
var doc = {
"name": "Test123",
"organisation": "Rat"
}, // document to update. Note: the doc here matches the existing array
query = { "email": "email@address" }; // query document
query["history.name"] = doc.name; // create the update query
query["history.organisation"] = doc.organisation;
var update = db.users.findAndModify({
"query": query,
"update": {
"$set": {
"history.$.name": doc.name,
"history.$.organisation": doc.organisation
}
}
}); // return the document modified, if there's no matched document update = null
if (!update) {
db.users.update(
{ "email": query.email },
{ "$push": { "history": doc } }
);
}
对匹配的文档执行此操作后,查询集合将产生相同的结果
db.users.find({ "email": "email@address" });
Output:
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "email@address",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
}
]
}
现在考虑不匹配的文档:
var doc = {
"name": "foo",
"organisation": "bar"
}, // document to update. Note: the doc here does not matches the current array
query = { "email": "email@address" }; // query document
query["history.name"] = doc.name; // create the update query
query["history.organisation"] = doc.organisation;
var update = db.users.findAndModify({
"query": query,
"update": {
"$set": {
"history.$.name": doc.name,
"history.$.organisation": doc.organisation
}
}
}); // return the document modified, if there's no matched document update = null
if (!update) {
db.users.update(
{ "email": query.email },
{ "$push": { "history": doc } }
);
}
查询此文档的此集合
db.users.find({ "email": "email@address" });
会产生
Output:
{
"_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
"email" : "email@address",
"__v" : 0,
"history" : [
{
"name" : "Test123",
"organisation" : "Rat",
"field" : 4,
"another" : 3
},
{
"name" : "foo",
"organisation" : "bar"
}
]
}