因爲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。
謝謝史蒂夫的回答。我還有其他問題: 1.爲什麼您使用ReferenceField而不是EmbeddedDocument for Service集合? 2.我需要存儲總和,並且在每次訪問數據時都不會隨時計算它。可能是現場權重服務可以使用pre_save信號來填充,只有當組件被添加/修改/刪除時才執行總和。你怎麼看待這件事? –
由於EmbeddedDocuments未存儲在其自己的集合中,但存儲在父級文檔集合中。如果有多個項目,將文檔放在集合中可以使一些查詢和索引變得更容易。我同意這些信號是正確的選擇,我將編輯答案以顯示該方法。 –
再次感謝你史蒂夫!如果有一個信號可以在upsert更新中使用,那就太好了。 –