2

所以我希望我的集合中的文档在结构上看起来像这样:

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

谢谢

4

1 回答 1

3

如果没有包含数组的相应查询字段,则无法应用位置运算符,但您需要位置运算符知道系统数组中对$addToSet {"metrics": ["TEST"]}的索引。您也不能根据 查询{"systems._id": "1338"},因为该字段可能尚不存在于文档中{"_id": "123"}。因此,如果我们不能组合多个涉及相同字段的操作,则不可能在单个请求中执行此操作,但我们不能在 update 中有冲突的 mod

最后的希望是如果我们在更新文档语法中有类似于$where 运算符的东西,以允许我们执行任意 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. 您可以按顺序运行这两个查询。但是,如果您有多个客户端访问您的数据库,这是不安全的。

于 2013-05-18T02:23:43.753 回答