2016-05-23 15 views
2

Ich versuche, eine gute Dokumentstruktur zu schaffen, die gute Leseleistungen und nicht so langsam Schreibleistungen hat. Ich muss Informationen über ein UserConnection-Dokument speichern, das die Verbindung zwischen zwei Benutzern in meiner Datenbank darstellt. Jeder Link hat eine Gewichtung, die von einer Liste von Parametern abhängt. Was ist die bessere mongodb Dokumentstruktur?

Das folgende ist ein Schema, das die Daten, die Links und Gewichte Komponenten darstellt:

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) 

Ich bin derzeit Mongoengine in Django. Ich habe versucht, eine Struktur mit EmbeddedDocument und EmbeddedDocumentListField zu definieren, aber ich bin nicht glücklich darüber.

Ich füge meine Tests der Kürze halber nicht hinzu.

Kann mir bitte jemand helfen, eine gute Struktur für MongDB zu finden?

Vielen Dank.

Antwort

2

Da Mongoengine die Dokumentstruktur in Python-Klassen definiert, können Sie mit den normalen python-Klassen dekorierte Methoden berechnete Werte zurückgeben.

Betrachten Sie das folgende Beispiel:

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]) 

Wenn Sie ein UserConnection Objekt haben, können Sie dann Zugriff auf eine weight Attribut:

>>> uc = UserConnection.objects.first() 
>>> uc.weight 
0.8544546532 

Der Nachteil dabei ist, dass weight nie auf der Datenbank gespeichert ist im Zusammenhang mit einer UserConnection, so dass Sie es nicht aggregieren oder auf dieser Ebene sortieren können, aber die aggregation framework kann einige gute Optionen bieten. Wenn Sie das Gewicht gespart haben brauchen, dann könnte man es definieren einige signals aufzunehmen, bevor das Dokument gespeichert wird:

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) 

Ein Nachteil dabei ist, dass Sie die save Methode aufrufen müssen, die update mit einem upsert=True Mittel tun erstellt die Gewichte nicht.

Ob Sie eingebettete vs. Referenz verwenden, hängt von what else you want to do with the data ab.

+0

Danke Steve für Ihre Antwort. Ich habe andere Frage darüber: 1. warum Sie ReferenceField und nicht EmbeddedDocument für Service Collection verwendet? 2. Ich muss die Summe speichern und nicht jedes Mal neu berechnen, wenn ich auf die Daten zugreife. Möglicherweise kann das Feldgewicht in Service mit einem pre_save-Signal gefüllt werden, um die Summe nur dann zu berechnen, wenn eine Komponente hinzugefügt/geändert/entfernt wird. Was denkst du darüber? –

+0

Da EmbeddedDocuments nicht in einer eigenen Sammlung gespeichert sind, sondern in der übergeordneten Dokumentensammlung gespeichert sind. Wenn Dokumente in einer Sammlung vorhanden sind, kann die Abfrage und Indizierung ein wenig einfacher sein, wenn viele Elemente vorhanden sind. Ich stimme den Signalen als die richtige Wahl zu, ich werde die Antwort bearbeiten, um diese Vorgehensweise ebenfalls zu zeigen. –

+0

Nochmals vielen Dank Steve! Es wäre schön, ein Signal zu haben, das auch in update mit upsert verwendet werden kann. –

Verwandte Themen