是否可以在同一更新中多次使用$ addToSet?

时间:2013-05-16 18:51:02

标签: python mongodb sql-update pymongo

所以这就是我希望我的集合中的文档看起来像结构:

{
    "_id": "123",
    "systems": [
        {
            "_id": "1338",
            "metrics": [
                "TEST"
            ]
        }
    ]
}

我的目标是能够为系统和/或度量在各自阵列中存在/不存在的任何实例执行单个更新/插入(使用upsert = True)。目前我唯一的工作是如下更新电话:

if not collection.find_one({"_id": "123", "systems._id": "1338"}):
    collection.update(
        {"_id": "123"}, 
        {"$addToSet": {"systems": {"_id": "1338"}}}, 
        upsert=True)
collection.update(
    {"_id": "123", "systems._id": "1338"}, 
    {"$addToSet": {"systems.$.metrics": "TEST"}}, 
    upsert=True)

由于

1 个答案:

答案 0 :(得分:3)

cannot apply the positional operator without a corresponding query field containing an array,但您需要位置运算符才能将系统数组中的索引知道为 $ addToSet {"metrics": ["TEST"]}。您也无法根据{"systems._id": "1338"}进行查询,因为文档{"_id": "123"}中可能尚不存在此字段。因此,如果我们无法组合触及相同字段的多个操作,则无法在单个请求中执行此操作,但我们无法have conflicting mods in update

最后的希望是,如果我们在更新文档语法中有类似$where operator的内容,则允许我们执行任意JavaScript来更新文档。我怀疑我们没有(也不会)有这个。

主要问题是systems字段上的数组索引。您可以使用_id属性作为新索引来重新设计架构以摆脱此索引:

{
    "_id": "123",
    "systems": {
        "1338": {
            "metrics": [
                "TEST"
            ]
        }
    }
}

通过此更改,您可以在一个操作中执行所有操作:

db.test.update({_id: "123"}, {$addToSet: {"systems.1338.metrics": "TEST"}}, {upsert: true})

另一种选择是使用以下设计:

{
    "_id": "123",
    "systems": {
        "metrics": {
            "1338": [
                "TEST"
            ]
        }
    }
}

最好的设计取决于你打算做什么。

编辑:

您还可以选择在应用程序中本地更新文档,然后将其发送回数据库,但是此选项可能无法提供我认为您的目标的原子性。

关于你目前的工作:你不需要if。您可以按顺序运行两个查询。但如果您有多个客户端访问您的数据库,则不安全。