是否可以在同一个更新中多次使用 $addToSet? [英] Is it possible to utilize $addToSet multiple times in the same update?

查看:52
本文介绍了是否可以在同一个更新中多次使用 $addToSet?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以这是我希望我的集合中的文档在结构上的样子:

So here is what I want the documents in my collection to look like structurally:

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

我的目标是能够对系统和/或指标在其各自的阵列中确实/不存在的任何实例执行单个更新/插入(使用 upsert=True).目前我唯一的解决方法是按如下方式更新调用:

My goal is to be able to do a single update/insert (using upsert=True) for any instance that the system and/or metric does/doesn't exist in their respective arrays. Currently my only work around is making to update calls as follows:

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)

谢谢

推荐答案

如果没有包含数组的相应查询字段,您不能应用位置运算符,但您需要位置运算符知道系统数组中的索引 $addToSet {"metrics": ["TEST"]}.您也不能基于 {"systems._id": "1338"} 进行查询,因为文档中可能还不存在该字段 {"_id": "123"}.因此,如果我们不能将涉及相同字段的多个操作组合在一起,则不可能在单个请求中完成,但我们不能在更新.

You cannot apply the positional operator without a corresponding query field containing an array, but you need the positional operator to know the index in the systems array to $addToSet {"metrics": ["TEST"]}. You cannot also query based on {"systems._id": "1338"}, because this field might not exist yet in the document {"_id": "123"}. Thus, it's not possible to do it in a single request if we cannot combine multiple operations touching the same fields, but we cannot have conflicting mods in update.

最后的希望是,如果我们有类似于 $where operator<update document 语法中的/a> 允许我们执行任意 JavaScript 来更新文档.我怀疑我们没有(也不会)有这个.

A last hope would be if we had something similar to the $where operator in the update document syntax to allow us to execute arbitrary JavaScript to update the document. I suspect that we don't (and won't) have this.

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

The main problem is the array index on systems field. You can redesign your schema to get rid of this index, using the _id attribute as the new index:

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

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

With this change, you could do all in one operation:

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

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

Another option is to use the following design:

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

最佳设计取决于您打算做什么.

The best design depends on what you intend to do.

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

You also have the option to update the document locally in your application and then send it back to the DB, but this option may not offer the kind of atomicity that I think you aim.

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

And about your current work around: You don't need the if. You can run both queries in order. But it's insecure if you have more than one client acessing your database.

这篇关于是否可以在同一个更新中多次使用 $addToSet?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆