所以这就是我希望我的集合中的文档看起来像结构:
{
"_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)
由于
答案 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
。您可以按顺序运行两个查询。但如果您有多个客户端访问您的数据库,则不安全。