2016-05-23 4 views
2

私は、優れた読み上げパフォーマンスを持つ優れたドキュメント構造を作成しようとしています。 データベース内の2人のユーザー間のリンクを表すUserConnectionドキュメントに関する情報を格納する必要があります。各リンクは、パラメータのリストに依存する重み付けをしています。より良いmongodbドキュメント構造は何ですか?

次は、データ、リンク、および重みのコンポーネントを表しスキーマです:

UserConnection  Services   Components 
    UserA    Name    Name 
    UserB    Weight   Weight 
    Weight   Components 
    Services 

UserConnection.Weight = sum(UserConnection.Services.Weight) 
UserConnection.Services.Weight = sum(UserConnection.Services.Weight.Components) 

私は現在、ジャンゴにMongoengineを使用しています。私は、EmbeddedDocumentとEmbeddedDocumentListFieldを使っていくつかの構造体を定義しようとしましたが、私はそれについて幸せではありません。

私は簡潔にするために私のテストを追加していません。

誰でもMongDBの良い構造を見つけるのに手伝ってもらえますか?

ありがとうございます。

答えて

2

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=Trueupdateをやって意味saveメソッドを呼び出す必要があるということです重みを作成しません。

埋め込みと参照のどちらを使用するかは、what else you want to do with the dataに依存します。

+0

あなたの答えはスティーブありがとうございます。私はそれについて他の質問があります: 1.なぜReferenceFieldを使用し、EmbeddedDocument for Serviceコレクションを使用していませんか? 2.データにアクセスするたびに合計を保存し、それを即座に計算する必要はありません。サービスへのフィールドウェイトは、コンポーネントが追加/変更/削除された場合にのみ、合計を行うためにpre_save信号を使用して書き込むことができます。あなたはそれについてどう思いますか? –

+0

埋め込みドキュメントは独自のコレクションには格納されませんが、親ドキュメントコレクションには格納されています。コレクションにドキュメントを置くと、多くのアイテムがある場合にクエリやインデックス作成を少し楽にすることができます。私はシグナルが正しい選択であることに同意し、そのアプローチを示すために答えを編集します。 –

+0

もう一度スティーブありがとう! upsertで更新する際にも使用できるシグナルがあるといいでしょう。 –

関連する問題