我刚刚遇到了一个场景,我不知道如何用我的文档的现有结构来解决。如下所示,我显然可以通过一些重构来解决这个问题,但我很好奇如何以最有效的方式解决这个问题并尊重相同的结构。
请注意,这个问题与如何在 MongoEngine 的 ListField 中的 EmbeddedDocument 上进行原子更新不同?
让我们假设以下模型:
class Scans(mongoengine.EmbeddedDocument):
peer = mongoengine.ReferenceField(Peers, required=True)
site = mongoengine.ReferenceField(Sites, required=True)
process_name = mongoengine.StringField(default=None)
documents = mongoengine.ListField(mongoengine.ReferenceField('Documents'))
is_complete = mongoengine.BooleanField(default=False)
to_start_at = mongoengine.DateTimeField()
started = mongoengine.DateTimeField()
finished = mongoengine.DateTimeField()
class ScanSettings(mongoengine.Document):
site = mongoengine.ReferenceField(Sites, required=True)
max_links = mongoengine.IntField(default=100)
max_size = mongoengine.IntField(default=1024)
mime_types = mongoengine.ListField(default=['text/html'])
is_active = mongoengine.BooleanField(default=True)
created = mongoengine.DateTimeField(default=datetime.datetime.now)
repeat = mongoengine.StringField(choices=REPEAT_PATTERN)
scans = mongoengine.EmbeddedDocumentListField(Scans)
当且仅当扫描字段的所有元素(扫描嵌入文档的列表)又具有唯一的文档列表时,我想做的是插入一个 ScanSettings 对象?唯一是指数据库级别列表中的所有元素,而不是整个列表 - 这很容易。
用简单的英语来说,如果在插入 ScanSetting 时,扫描列表的任何元素都有一个扫描实例,其中文档列表是重复的,那么这种插入不应该发生。我的意思是数据库级别的唯一性,考虑到现有记录(如果有的话)。
鉴于 Mongo 不支持同一文档中列表的所有元素的唯一性,我找到了两种解决方案:
选项 A
我重构了我的“模式”并使 Scans 集合继承自 Document 而不是 Embedded 文档,并将 ScanSettings 的扫描字段更改为 ReferenceFields 的 ListField 以扫描文档。然后很容易,因为我只需要先使用“更新”和操作符“add_to_set”和选项“upsert=True”来保存扫描。然后,一旦操作被批准,保存 ScanSettings。我将需要扫描实例的数量来插入 + 1 个查询。
选项 B 我保留相同的“模式”,但以某种方式为扫描嵌入文档生成唯一 ID。然后在使用非空扫描字段插入任何扫描设置之前,我将获取已经存在的记录,以查看在刚刚检索到的记录和要插入的记录中是否存在重复的文档 ObjectId。换句话说,我会通过 Python 而不是使用 MogoneEngine/Mongodb 检查唯一性。我将需要 2 x 数量的扫描实例来插入(读取 + 使用 add_set_operator 更新)+ 1 ScanSettings 保存
选项 C 忽略唯一性。考虑到我的模型的结构,我很确定不会有重复,或者如果有的话,它可以忽略不计。然后在阅读时处理重复项。对于像我这样来自关系数据库的人来说,这个解决方案感觉很麻烦。
我是 Mongo 的新手,所以我很感激任何评论。谢谢。
PS:我正在使用最新的 MongoEngine 和免费的 Mongodb。
提前非常感谢。