mongoengineはpythonクラスのドキュメント構造を定義するので、通常のpythonクラス@property
の装飾されたメソッドを使用して計算値を返すことができます。あなたがUserConnection
オブジェクトを持っている場合
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])
は、あなたがして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)
をこれの欠点は、あなたがupsert=True
でupdate
をやって意味save
メソッドを呼び出す必要があるということです重みを作成しません。
埋め込みと参照のどちらを使用するかは、what else you want to do with the dataに依存します。
あなたの答えはスティーブありがとうございます。私はそれについて他の質問があります: 1.なぜReferenceFieldを使用し、EmbeddedDocument for Serviceコレクションを使用していませんか? 2.データにアクセスするたびに合計を保存し、それを即座に計算する必要はありません。サービスへのフィールドウェイトは、コンポーネントが追加/変更/削除された場合にのみ、合計を行うためにpre_save信号を使用して書き込むことができます。あなたはそれについてどう思いますか? –
埋め込みドキュメントは独自のコレクションには格納されませんが、親ドキュメントコレクションには格納されています。コレクションにドキュメントを置くと、多くのアイテムがある場合にクエリやインデックス作成を少し楽にすることができます。私はシグナルが正しい選択であることに同意し、そのアプローチを示すために答えを編集します。 –
もう一度スティーブありがとう! upsertで更新する際にも使用できるシグナルがあるといいでしょう。 –