【问题标题】:Update an Element if Position is Unknown with Upsert如果位置未知,则使用 Upsert 更新元素
【发布时间】:2014-04-28 12:30:40
【问题描述】:

看来您(/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 尝试将文档作为新文档插入,因为 find 查询在其 'events.ids': '176976332' 部分 (cheat) 上失败。

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

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    是的,但是您以错误的方式进行操作。与其“查找”不确定是否存在的元素,不如尝试应用$addToSet 运算符:

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

    还请注意,positional $ 运算符文档中的 $ 运算符不应与“upserts”一起使用,因为这将导致字段名称被解释为“文字”(其中包括 @ 中的值) 987654328@ ),这将是插入到文档中的实际字段。

    尝试确保您的数组“插入/更新插入”操作指定了整个数组内容以使其正常工作。

    另一个适应是"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" }
                }
            }
        ]
    })
    

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

    【讨论】:

    • 嗯,只有在updates 命令中接受$ 时,如果您的第二部分类似于:{ "q": { "_id": ObjectId("535e3ab9c36b4417d031402f"),'events.ids': '176976332' }, "u": {"$set": { "events.$.foo": "bar" } } },该怎么办?我管理的(没有批量)是首先使用$set 和upsert=false,如果这失败了$addToSet 它(就像你在第一次更新时所做的那样)。现在的事情是衡量哪个更好(对于服务器资源和延迟):使用批量 API 对每个子文档始终进行 2 个查询,或者检查带有位置 $ 的 $set 是否失败,因此使用 $addToSet。
    • @Diolor 类似的东西,但如果你想使用具有相同排序或“批量”构造的位置更新,那么它应该是最后一次尝试的操作。了解如果数组中不存在该元素,则任何“upsert”将创建一个新记录。并且查询中指定的_id 值会导致重复键错误。明白了吗?
    • 是的。好吧,这取决于一个人的需要是否会变得危险。如果确定文档始终存在(我的情况),则没有必要使用 upsert。知道了。谢谢
    • @Diolor 很高兴你“明白了”并且你发现这很有用:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-05
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    相关资源
    最近更新 更多