MongoEngine - 从ListField中按ID提取引用

4 投票
1 回答
4584 浏览
提问于 2025-04-17 14:41

我想从一个 ListField(ReferenceField) 中删除一些引用,主要是根据它们的值来决定。

我在以下模型中存储关于图片的信息:

class ImageUrl(Document):
    src = UrlField()
    counter = IntField()
    deleted = BooleanField()

我们在一个叫做 WebpageEmbeddedDocument 中存储在页面上遇到的图片的 id

class Webpage(EmbeddedDocument):
    image_list = ListField(ReferenceField(ImageUrl))
    ...

最后,Website 模型被嵌入到一个 RawData 模型中:

class RawData(Document):
    ...
    webpage = EmbeddedDocumentField(Webpage)

我想根据一些属性(比如:计数器值超过1)从 RawData 记录中删除对 ImageUrl 记录的引用,然后将这些 ImageUrl 记录的 deleted 属性设置为 True

我正在做:

images = ImageUrl.objects((Q(deleted=False) & Q(counter__gt=1)).all()
for image in images:
    # all RadData records containing the image in their image list
    for rdata in RawData.objects(webpage__image_list__in=[image.id]:
        # remove image from the image_list
        RawData.objects(id=rdata.id).update_one(pull__webpage__image_list=image.id)
    # set 'deleted=True' on the ImageUrl record
    ImageUrl.objects(id=image.id).update_one(set__deleted=True)

但是,pull 操作出现了以下错误: OperationError: Update failed [Cannot apply $pull/$pullAll modifier to non-array]

根据我从 http://docs.mongodb.org/manual/reference/operator/pull/#_S_pull如何通过ID从MongoEngine的列表(ListField)中删除项目? 理解的,我需要指定要从中删除值的数组的键。然而,在我的情况下,我想从一个列表中删除一个值……我该怎么做呢?

非常感谢你的时间!

1 个回答

5

位置操作符的工作方式是,它允许你在一个列表中查找某个值,然后对这个值的第一个出现实例进行操作,通常是更新。$pull 会从列表中删除所有的实例,这正是你想要的效果。

在使用mongoengine时,如果有引用,你可以直接传入实例对象,比如:

for rdata in RawData.objects(webpage__image_list=image):
    # remove image from the image_list
    rdata.update_one(pull__webpage__image_list=image)

我整理了一下代码,去掉了重复的查询 - 因为你已经有了rdata,所以不需要再去找那个文档了!

OperationError: Update failed [Cannot apply $pull/$pullAll modifier to non-array] 这意味着你正在尝试删除需要数组的数据,但有一个文档的image_list实际上并不是一个数组。这可能是因为在磁盘上有一个文档的image_list并不是一个列表。如果你加一个try except块,就可以查看那个失败的文档,看看是不是这种情况,如果是的话,就需要手动迁移一下。

撰写回答