2016-03-24 5 views
1

Ich weiß, dass dies gegen das Design von MongoDB und seinem No-SQL-Modell geht, aber ich versuche, Dokumente in einer Sammlung zu suchen und dann das ID-Feld aus den Ergebnissen zu suchen entsprechende Datensätze in einer anderen Sammlung. Effektiv versuchen, einen Join zu emulieren.MongoDB, Mongoose Ergebnisse von einem Find, um eine andere Sammlung zu suchen

//query is irrelevant to question 
var results = collectionOne.find(query).limit(limit); 

var a = []; 

results.forEach(function(r) 
{ 
    var aquery = { id : {$eq : r.id}}; 
    collectionTwo.find(aquery).limit(limit).exec(function, b) 
    { 
     if (err) 
     { 
      res.render('error', 
      { 
       status : 500 
      }); 
     } 
     else 
     { 
      a.push(b); 
     } 
    }); 
}); 
res.jsonp(a); 
+0

Sie können die Aggregation mit $ lookup verwenden, um diese Serverseite auszuführen – profesor79

Antwort

6

Zwar gibt es neue Funktionen in MongoDB wie $lookup, das tut eine „Art von Join“, Ihre spezifischen Betrieb bedeutet dies nicht brauchen. Alles, was Sie hier tun, ist das Zurückgeben von Ergebnissen aus einer anderen Sammlung basierend darauf, wo der _id Wert aus dem vorherigen Wert erstellt wurde.

Hierfür ist die beste Option eine mehr Abfrage auf die andere Sammlung mit $in.

// Mongoose turns a cursor to an array by default in the callback method 
collectionOne.find(query,{ "_id": 1}).limit(limit).exec(function(err,results) { 

    // Just get array of _id values 
    var ids = results.map(function(el) { return el._id }); 

    // Not sure if you really mean both collections have the same primary key 
    // I'm presuming two different fields being "id" as opposed to "_id" 
    collectionTwo.find({ "id": { "$in": ids } },function(err,items) { 
     // matching results are here 
    }) 

}) 

Das ist es.

Alles, was Sie tun, ist Ihre ersten Abfrage-Ergebnisse von _id Werten als „Liste“ Rückkehr von nur das, liefert dann dieses Argument zu $in auf dem verwandten Gebiet in der Zielsammlung

Wenn Sie wirklich ein „anschließen wollten "und haben MongoDB 3.2 verfügbar ist, dann können Sie $lookup wie diese

collectionOne.aggregate([ 
    { "$match": query }, 
    { "$limit": limit }, 
    { "$lookup": { 
     "from": "collectionTwo", 
     "localField": "_id", 
     "foreignField": "id", 
     "as": "twoItems" 
    }} 
]) 

verwenden, das ist ein tatsächliches‚‘Ergebnis verbunden, und obwohl man konnte möglicherweise es verwenden, um nur die angepassten Ergebnisse von collectionTwo zurück, dann ich Persona ly nicht. Es ist eine kostspielige Übung sogar auf dem Server, und die weitere Filterung einer Manipulation, die erforderlich ist, um dieses Format tatsächlich zurückzugeben, kostet am Ende noch mehr.

Sie könnten auch über .populate() in Mungo lesen, die eigentlich die "Reverse" dieser Art von Abfrage ist. Stattdessen besteht der Prozess darin, ein Array (oder ein reguläres Feld, aber in diesem Fall ein Array) von ObjectId Werten zu speichern, die auf den Primärschlüssel von Objekten in der zugehörigen Sammlung zeigen. Wenn also "viele" Werte für collectionTwo vorhanden wären, würden diese in einem Array innerhalb von collectionOne Dokumenten gespeichert werden.

Wieder ist dies eine "Join-Emulation" und kein echter Join. Das Ergebnis wäre ähnlich dem $lookup, und wieder ist nicht wirklich "nur" die Ergebnisse aus collectionTwo, sondern die "beigetretene" Version, die Sie ähnlich filtern müssten.

Alles, was wirklich passiert mit .populate() ist, dass es eine $in Abfrage sowieso ausgeführt wird. Selbst nach der ganzen Arbeit, Kind-Referenzen in einem Elternteil zu speichern (ein IMHO, in den meisten Fällen, wenn Sie das tun können, können Sie stattdessen auch einfach die Daten einbetten), bleibt die tatsächliche Interaktion mit der Datenbank unverändert, da sie immer noch ein tut $in Abfrage.

+0

@ user3424480 Nicht sicher, was Sie denken, dass Sie dort meinen. Wenn Sie meinen, dass wenn eine "Quelle" 'ObjectId' verwendet, dann muss das" Ziel "auch, dann natürlich. Dies gilt für jeden BSON-Typ. –

Verwandte Themen