2013-10-30 12 views
8

Ich verwende MongoDB mit einem Nodejs REST-Dienst, der meine gespeicherten Daten freilegt. Ich habe eine Frage darüber, wie meine Daten abgefragt werden, die $ ref verwendet.

Hier ist ein Beispiel für ein Objekt, das einen Verweis auf ein anderes Objekt (Detail) in Anthere Sammel enthält:

{ 
    "_id" : ObjectId("5962c7b53b6a02100a000085"), 
    "Title" : "test", 
    "detail" : { 
     "$ref" : "ObjDetail", 
     "$id" : ObjectId("5270c7b11f6a02100a000001") 
    }, 
    "foo" : bar 
} 

Tatsächlich verwenden Node.js und mongodb Modul, ich die folgenden:

db.collection("Obj").findOne({"_id" : new ObjectID("5962c7b53b6a02100a000085"}, 
function(err, item) { 
    db.collection(item.$ref).findOne({"_id" : item.$id}, function(err,subItem){ 
     ... 
    }); 
}); 

Tatsächlich mache ich 2 Abfragen und bekomme 2 Objekte. Es ist eine Art "faulen Laden" (nicht genau aber fast)

Meine Frage ist einfach: Ist es möglich, das gesamte Objekt Graph in einer Abfrage abzurufen?

Vielen Dank

Antwort

4

Nein, das geht nicht.

Um DBRefs aufzulösen, muss Ihre Anwendung zusätzliche Abfragen ausführen, um die referenzierten Dokumente zurückzugeben. Viele Treiber verfügen über Hilfsmethoden, die die Abfrage für den DBRef automatisch bilden. Die Treiber lösen DBRefs nicht automatisch in Dokumente auf.

Aus der MongoDB-Dokumentation http://docs.mongodb.org/manual/reference/database-references/.

+1

im Server veraltet sind und so weit ich die Knoten-mongodb-native Treiber weiß nicht, einen Weg hat diese zu lösen Refs für dich. – Brett

4

Ist es möglich, Elternobjekt zusammen mit seiner $ ref mit einzelnen MongoDB Abfrage abzurufen?

Nein, das ist nicht möglich. Mongo haben keine innere Unterstützung für Refs, so dass es zu Ihrer Anwendung, sie zu füllen (siehe Brett's answer).

Aber ist es möglich, Elternobjekt mit all seinen Referenzen mit einem einzigen node.js Befehl zu holen?

Ja, es ist möglich. Sie können es mit Mongoose tun. Es hat die Unterstützung der Bevölkerung von Build-ref. Sie müssen Ihr Datenmodell ein wenig ändern, damit es funktioniert, aber es ist genau das, wonach Sie suchen. Natürlich macht Mongoose die gleichen zwei MongoDB-Abfragen, die Sie auch gemacht haben.

1

Nein, sehr wenige Treiber für MongoDb enthalten spezielle Unterstützung für eine DBRef. Es gibt zwei Gründe:

  1. MongoDb hat keine speziellen Befehle, um den Abruf referenzierter Dokumente zu ermöglichen. Treiber, die Unterstützung hinzufügen, füllen künstlich die resultierenden Objekte.
  2. Je mehr, "Bare Metal" die API, desto weniger sinnvoll. In der Tat, als. MongoDb-Sammlungen sind schemalos, wenn der NodeJs-Treiber das primäre Dokument mit allen realisierten Referenzen zurückbrachte, wenn der Code dann das Dokument ohne Unterbrechung der Referenzen speicherte, würde dies zu einem eingebetteten Filialdokument führen. Natürlich wäre das ein Durcheinander.

Sofern Ihre Feldwerte nicht variieren, würde ich mich nicht mit einem DBRef Typ befassen und würde stattdessen nur die ObjectId direkt speichern.Wie Sie sehen können, bietet ein DBRef wirklich keinen Vorteil, außer dass viel doppelt vorhandener Speicherplatz für jede Referenz benötigt wird, da ein reicheres Objekt zusammen mit seinen Typinformationen gespeichert werden muss. In jedem Fall sollten Sie den möglicherweise unnötigen Aufwand berücksichtigen, um eine Zeichenfolge zu speichern, die die Dokumente der referenzierten Sammlung enthält.

Viele Entwickler und MongoDb, Inc. haben eine Objektdokument-Mapping-Schicht über den vorhandenen Basistreibern hinzugefügt. Eine beliebte Option für MongoDb und Nodejs ist Mongoose. Da der MongoDb-Server die referenzierten Dokumente nicht wirklich kennt, wird die Verantwortung der Referenzen auf den Client übertragen. Da es üblich ist, konsistent eine bestimmte Sammlung von einem bestimmten Dokument zu referenzieren, ermöglicht es Mongoose, die Referenz als ein Schema zu definieren. Mungo ist nicht schemalos.

Wenn Sie akzeptieren, ein Schema zu haben und zu verwenden, ist Mungo definitiv einen Blick wert. Es kann effizient einen Stapel verwandter Dokumente (aus einer einzelnen Sammlung) aus einer Reihe von Dokumenten abrufen. Es verwendet immer den nativen Treiber, aber es führt Operationen im Allgemeinen äußerst effizient aus und entlastet die komplexeren Anwendungsarchitekturen.

Ich würde vorschlagen, dass Sie einen Blick auf die populate Methode (here) werfen, um zu sehen, was es kann.

Demo  /* Demo would be a Mongoose Model that you've defined */ 
.findById(theObjectId) 
.populate('detail') 
.exec(function (err, doc) { 
    if (err) return handleError(err); 
    // do something with the single doc that was returned 
}) 

Wenn statt findById, die immer ein einzelnes Dokument zurückgibt, wurden find verwendet, mit populate, alle zurück details Eigentum Dokumente werden automatisch ausgefüllt werden. Es ist auch schlau, dass es dieselben referenzierten Dokumente mehrmals anfordern würde. Wenn Sie Mongoose nicht verwenden, sollten Sie eine Caching-Schicht in Betracht ziehen, um möglichst keine clientseitigen Referenzverbindungen zu verwenden und den Abfrageoperator so viele Stapel wie möglich zu verwenden.

+0

Danke, ich sehe mir Mungo an. –

1

erreiche ich das gewünschte Ergebnis mit dem nächsten Beispiel:

collection.find({}, function (err, cursor) { 
    cursor.toArray(function (err, docs) { 
     var count = docs.length - 1; 
     for (i in docs) { 
      (function (docs, i) { 
       db.dereference(docs[i].ref, function(err, doc) { 
        docs[i].ref = doc; 
        if (i == count) { 
         (function (docs) { 
          console.log(docs); 
         })(docs); 
        } 
       }); 
      })(docs, i) 
     } 
    }); 
}); 

nicht sicher, dass es Lösung Beste vom Besten ist, aber es ist einfachste Lösung, die ich gefunden.