如果使用Upsert定位未知,则更新元素

时间:2014-04-28 12:30:40

标签: mongodb mongodb-query

看起来你(/ I)不能同时拥有upsert array element update operation

如果你这样做(python):

findDct = {
  "_id": ObjectId("535e3ab9c36b4417d031402f"),
  'events.ids': '176976332'
}
print col.update(findDct, {"$set" : {"events.$.foo": "bar"} }, upsert=True)

它将抛出:

pymongo.errors.DuplicateKeyError: insertDocument :: caused by :: 11000 E11000 
duplicate key error index: test.col.$_id_  dup key: { : ObjectId('535e3ab9c36b4417d031402f') }

这是因为" _id"当然是一个索引,mongo尝试将文档作为新文件插入,因为查找查询在其'events.ids': '176976332'部分(cheat)上失败。

是否可以使用upsert True / how更新数组中的未知元素?

1 个答案:

答案 0 :(得分:0)

是的,但是你会以错误的方式解决它。而不是发现"发现"您不确定它是否存在的元素,然后尝试应用$addToSet运算符:

db.collection.update(
    { "_id": ObjectId("535e3ab9c36b4417d031402f" },
    {
        "$addToSet": { "events": { "foo": "bar" } }
    },
    { "upsert": true }
)

请在positional $运营商文档中注明,您不应将$运算符用于" upserts"因为这将导致字段名称被解释为"字面值" (包括"events.$.foo"中的值),这将是插入到文档中的实际字段。

尝试确保您的阵列"插入/上传"操作指定整个数组内容以使其工作。

另一个改编是使用"bulk"方法,pymongo驱动程序已经有一个很好的API,但这是一般的形式:

db.runCommand({
    "update": "collection",
    "updates": [
        {
            "q": { "_id": ObjectId("535e3ab9c36b4417d031402f" } },
            "u": {
                "$addToSet": { 
                    "events": {
                        "foo": "bar", "bar": "baz"
                    }
                }
            },
            "upsert": true
        },
        {
            "q": { "_id": ObjectId("535e3ab9c36b4417d031402f" } },
            "u": {
                "$set": { "events.foo": "bar" }
            }
        }
    ]
})

但是如果你能清楚地看到那里的情况,你仍然非常小心,你不会在子文档数组中产生重复项。但它是一种方法,因为即使第一个表单无法添加任何内容,每个更新也会级联。不是最好的例子,但我希望你明白这一点。