如果条目不包含两个匹配

时间:2016-06-14 14:43:51

标签: arrays mongodb upsert database

我有一个mongo文档,其中包含一个名为history的数组:

{
    "_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
    "email" : "email@address",
    "__v" : 0,
    "history" : [ 
        {
            "name" : "Test123",
            "organisation" : "Rat",
            "field" : 4,
            "another": 3
        }
    ]
}

我想为每个历史记录对象添加字段或更新字段 IF 名称和组织匹配,但是如果他们不匹配,我想要使用查询的名称向数组添加新对象并在必要时组织并添加/更新对象的其他字段。

所以:

此查询找到匹配的内容:

db.users.find({ 
    email:"email@address",
    $and: [
        { "history.name": "Test123", "history.organisation": "Rat"}
    ]
})

但是,如果数组中没有history.name和history.organisation的组合,我很难让update / upsert工作。

我认为我需要做的是:

“如果此历史名称不等于'Test123'且历史记录组织不等于'Rat',则将对象添加到包含更新查询中提供的那些字段和任何其他字段的数组中。”

我试过了:

db.users.update({ 
    email:"email@address",
    $and: [
        { "history.name": "Test123", "history.organisation": "Rat"}
    ]
}, {
    history: { name: "Test123"},
    history: { organisation: "Rat"}
}, {upsert:true})

但那给了我E11000 duplicate key error index: db.users.$email_1 dup key: { : null }

非常感谢任何帮助。

感谢社区!

1 个答案:

答案 0 :(得分:0)

使用单个原子更新是不可能的我担心,您必须执行几个满足这两个条件的更新操作。

将更新逻辑分解为两个不同的更新操作,第一个需要使用positional $ operator来识别所需的history数组中的元素以及 $set 更新现有字段。此操作遵循逻辑 更新字段,如果名称和组织匹配

现在,您希望将 findAndModify() 方法用于此操作,因为它可以返回更新的文档。默认情况下,返回的文档不包括对更新所做的修改。

因此,有了这个武器库,你可以在下一个操作中探测你的第二个逻辑,即 更新IF" history.name"和" history.organisation"不存在于数组 中。有了这第二个 更新操作,您需要使用 $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" });

<强>输出:

{
    "_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" });

会产生

<强>输出:

{
    "_id" : ObjectId("575fe85bfe98c1fba0a6e535"),
    "email" : "email@address",
    "__v" : 0,
    "history" : [ 
        {
            "name" : "Test123",
            "organisation" : "Rat",
            "field" : 4,
            "another" : 3
        }, 
        {
            "name" : "foo",
            "organisation" : "bar"
        }
    ]
}