2016-05-23 91 views
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到Django的

。我試圖用EmbeddedDocument和EmbeddedDocumentListField來定義一些結構,但我對此並不滿意。

爲簡潔起見,我不添加我的測試。

任何人都可以請幫我找到一個好的MongDB結構?

謝謝。

回答

2

因爲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=Trueupdate將不會創建權重。

您是否使用嵌入式與參考取決於what else you want to do with the data

+0

謝謝史蒂夫的回答。我還有其他問題: 1.爲什麼您使用ReferenceField而不是EmbeddedDocument for Service集合? 2.我需要存儲總和,並且在每次訪問數據時都不會隨時計算它。可能是現場權重服務可以使用pre_save信號來填充,只有當組件被添加/修改/刪除時才執行總和。你怎麼看待這件事? –

+0

由於EmbeddedDocuments未存儲在其自己的集合中,但存儲在父級文檔集合中。如果有多個項目,將文檔放在集合中可以使一些查詢和索引變得更容易。我同意這些信號是正確的選擇,我將編輯答案以顯示該方法。 –

+0

再次感謝你史蒂夫!如果有一個信號可以在upsert更新中使用,那就太好了。 –

相關問題