由于 mongoengine 在 python 类中定义了文档结构,您可以使用普通的 python 类@property 装饰方法返回计算值。
考虑以下示例:
import mongoengine as mdb
mdb.connect("so-37396173")
class User(mdb.Document):
name = mdb.StringField()
class UserConnection(mdb.Document):
user_a = mdb.ReferenceField('User')
user_b = mdb.ReferenceField('User')
services = mdb.ListField(mdb.ReferenceField('Service'))
@property
def weight(self):
return sum([s.weight for s in self.services])
class Component(mdb.EmbeddedDocument):
name = mdb.StringField()
weight = mdb.FloatField()
class Service(mdb.Document):
name = mdb.StringField()
components = mdb.EmbeddedDocumentListField('Component')
@property
def weight(self):
return sum([c.weight for c in self.components])
当您拥有UserConnection 对象时,您可以访问weight 属性:
>>> uc = UserConnection.objects.first()
>>> uc.weight
0.8544546532
这样做的缺点是weight 永远不会在UserConnection 的上下文中存储在数据库中,因此您无法在该级别对其进行聚合或排序,但aggregation framework 可能会提供一些不错的选择.如果您需要保存权重,那么您可以定义一些 signals 以在保存文档之前包含它:
import mongoengine as mdb
mdb.connect("so-37396173")
class User(mdb.Document):
name = mdb.StringField()
class UserConnection(mdb.Document):
user_a = mdb.ReferenceField('User')
user_b = mdb.ReferenceField('User')
services = mdb.ListField(mdb.ReferenceField('Service'))
weight = mdb.FloatField()
@classmethod
def calc_weight(cls, sender, document, **kwargs):
document.weight = sum([s.weight for s in document.services])
mdb.signals.pre_save.connect(UserConnection.calc_weight, sender=UserConnection)
class Component(mdb.EmbeddedDocument):
name = mdb.StringField()
weight = mdb.FloatField()
class Service(mdb.Document):
name = mdb.StringField()
components = mdb.EmbeddedDocumentListField('Component')
weight = mdb.FloatField()
@classmethod
def calc_weight(cls, sender, document, **kwargs):
document.weight = sum([s.weight for s in document.components])
mdb.signals.pre_save.connect(Service.calc_weight, sender=Service)
这样做的一个缺点是您必须调用 save 方法,这意味着使用 upsert=True 执行 update 不会创建权重。
您是使用嵌入式还是参考取决于what else you want to do with the data。