如果满足多个条件中的至少一个,则更新特定数组元素

问题描述 投票:0回答:1

我正在尝试理解(并修复)一个不属于我的代码,它使用 PyMongo。

我们要查找带有

_id==_id
的文档,在其列表
comments
中,带有
id==comment_id
id==PyObjectId(comment_id)
的评论。 对于该评论,我们想添加一个答案。 在代码中:

await db_collection.update_one(
        filter=query, update=update, array_filters=array_filters
)

在哪里

query = {
    "_id": _id,
    "$or": [    
        {"comments": {"$elemMatch": {"id": comment_id}}},
        {"comments": {"$elemMatch": {"id": PyObjectId(comment_id)}}},
    ],
}

update = {
    "$set": {
        "comments.$[cmt].answer": jsonable_encoder(reply)
    }
}

array_filters = [{"cmt.id": comment_id}]

我的问题是

array_filters
只检查是否
id==comment_id
而不是
id == PyObjectId(comment_id)
,就像查询一样。 这样当我有一个
PyObjectId
作为id时,没有项目被更新。

我想我应该用类似的东西修改

array_filters

array_filters = [{"cmt.id": comment_id}, {"cmt.id": PyObjectId(comment_id)}]

array_filters = [{"$or$": [{ "cmt.id": comment_id}, {"cmt.id": PyObjectId(comment_id)}]}

但遗憾的是,我只能在生产环境中测试我的代码,并且我试图在破坏之前了解它的实际工作原理。

谢谢大家!

python mongodb pymongo
1个回答
1
投票

让我们看看这里发生了什么......

来自原始问题:

query = {
    "_id": _id,
    "$or": [    
        {"comments": {"$elemMatch": {"id": comment_id}}},
        {"comments": {"$elemMatch": {"id": PyObjectId(comment_id)}}},
    ],
}

update = {
    "$set": {
        "comments.$[cmt].answer": jsonable_encoder(reply)
    }
}

array_filters = [{"cmt.id": comment_id}]

查询使用的是

"$elemMatch"
,但由于单个字段只有一个条件,因此可以简化为:

query = {
    "_id": _id,
    "comments.id": {
        "$in": [comment_id, PyObjectId(comment_id)]
    },
}

如果我们假设(这里似乎有道理,但我们应该小心)

"id"
"comments"
数组中是唯一的,那么
"arrayFilters"
也不是必要的。所以
update
可以简化为:

update = {
    "$set": {
        "comments.$.answer": jsonable_encoder(reply)
    }
}

这里

$
使用
query
中的元素“匹配”并替换第一个仅第一个,匹配
"comments"
中的元素为
update
。如果
"comments"
数组的多个元素应该更新,这将不起作用(如果应该更新多个元素,请参见下面的
"arrayFilters"
的使用,因为
"id"
not 唯一的)。

因此,将所有这些与我们所做的假设放在一起:

query = {
    "_id": _id,
    "comments.id": {
        "$in": [comment_id, PyObjectId(comment_id)]
    },
}

update = {
    "$set": {
        "comments.$.answer": jsonable_encoder(reply)
    }
}

# possibly some other code here from the original app ...

await db_collection.update_one(
        filter=query, update=update
)

mongoplayground.net 上查看它如何处理伪造的文档。仅更新一个元素,即使存在重复的

"id"
值。

"arrayFilters"

如果

"id"
"comments"
数组中不是唯一的并且应该更新数组中的多个对象,那么可以使用
"arrayFilters"
来做到这一点。

query = {
    "_id": _id,
    "comments.id": {
        "$in": [comment_id, PyObjectId(comment_id)]
    },
}

update = {
    "$set": {
        "comments.$[cmt].answer": jsonable_encoder(reply)
    }
}

array_filters = [
    {
        "cmt.id": {
            "$in": [comment_id, PyObjectId(comment_id)]
        }
    }
]

# possibly some other code here from the original app ...

await db_collection.update_one(
        filter=query, update=update, array_filters=array_filters
)

在这里,任何与

"comments"
“匹配”的
"arrayFilter"
数组元素都将被更新。在 mongoplayground.net 上查看它是如何工作的。所有与
"arrayFilter"
“匹配”的元素都会更新。

© www.soinside.com 2019 - 2024. All rights reserved.