You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mongoengine中通过索引更新嵌入列表字段的元素?

问题:Mongoengine中通过索引更新嵌入列表字段的特定元素

我有一个使用GraphQL和Mongoengine的项目,想要更新嵌入列表字段中的特定元素,不想从客户端获取整个列表,而是希望仅获取新值、索引以及要更新的字段名。以下是示例Post模型:

class Tag(EmbeddedDocument):
   value = StringField()
   description = StringField()

class Post(Document):
    content = StringField()
    tags = EmbbeddedDocumentListField(Tag)  # 注意:此处拼写错误,应为EmbeddedDocumentListField

class PostRepository:
    def get(self, **kwargs):
        return Post.object.filter(**kwargs).first()  # 注意:应为Post.objects
    
    def update(self, query: dict, update_fields: dict):
        post = self.get(**query)
        post.modify(query=None, **update_fields)
        return post

我的解析器代码如下:

def update_post_resolver(id: str):
    post_repository = PostRepository()
    return post_repository.update({"id": id}, {"set__tags__0": {"value": "Python", "description": "..."}})

但运行时出现如下报错:

raise ValueError(
ValueError: The source SON object needs to be of type 'dict' but a '<class 'str'>' was found

raise InvalidQueryError(
mongoengine.errors.InvalidQueryError: Querying the embedded document Tag failed, due to an invalid query value

请问是否可以在Mongoengine中使用下划线关键字参数,通过索引更新特定的Tag元素?


解决方案

可以通过下划线关键字参数结合索引更新嵌入列表的特定元素,但你的写法存在问题,以下是修正方案:

1. 错误原因分析

你直接给set__tags__0传入字典,试图替换整个Tag对象,但Mongoengine要求你明确指定要更新的内嵌字段路径,而非直接传入完整的文档字典。另外注意模型中的两处拼写错误:EmbbeddedDocumentListField应为EmbeddedDocumentListField,Post.object应为Post.objects,这些错误也可能引发潜在问题。

2. 正确的更新写法

要更新内嵌列表中指定索引元素的字段,需要将路径细化到具体字段,格式为set__[列表字段名]__[索引]__[内嵌字段名]:

单字段更新

{"set__tags__0__value": "Python"}

多字段更新

{
    "set__tags__0__value": "Python",
    "set__tags__0__description": "..."
}

修正后的解析器代码:

def update_post_resolver(id: str):
    post_repository = PostRepository()
    return post_repository.update(
        {"id": id}, 
        {
            "set__tags__0__value": "Python",
            "set__tags__0__description": "..."
        }
    )

3. 更高效的数据库直接更新

如果不需要先获取文档对象,可以直接使用update_one方法在数据库层面更新,避免额外的查询开销:

更新仓库类方法:

class PostRepository:
    def get(self, **kwargs):
        return Post.objects.filter(**kwargs).first()
    
    def update_embedded_field(self, query: dict, index: int, update_data: dict):
        update_fields = {}
        for key, value in update_data.items():
            update_fields[f"set__tags__{index}__{key}"] = value
        Post.objects(**query).update_one(**update_fields)

解析器调用示例:

def update_post_resolver(id: str):
    post_repository = PostRepository()
    post_repository.update_embedded_field(
        {"id": id},
        0,
        {"value": "Python", "description": "..."}
    )
    return post_repository.get(id=id)

内容的提问来源于stack exchange,提问作者Muzaffer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:58:21