641 Stimmen

Wie führe ich den SQL-Join in MongoDB aus?

Wie führe ich den SQL-Join in MongoDB aus?

Nehmen wir an, Sie haben zwei Sammlungen (Benutzer und Kommentare), und ich möchte alle Kommentare mit pid=444 zusammen mit den Benutzerinformationen für jeden abrufen.

comments
  { uid:12345, pid:444, comment="blah" }
  { uid:12345, pid:888, comment="asdf" }
  { uid:99999, pid:444, comment="qwer" }

users
  { uid:12345, name:"john" }
  { uid:99999, name:"mia"  }

Gibt es eine Möglichkeit, alle Kommentare mit einem bestimmten Feld (z. B. ...find({pid:444}) ) und die mit jedem Kommentar verknüpften Benutzerinformationen in einem Rutsch zu finden?

Im Moment erhalte ich zuerst die Kommentare, die meinen Kriterien entsprechen, dann finde ich alle uid's in diesem Ergebnissatz heraus, erhalte die Benutzerobjekte und führe sie mit den Ergebnissen des Kommentars zusammen. Es scheint, dass ich das falsch mache.

67 Stimmen

Die letzte Antwort auf diese Frage ist wahrscheinlich die wichtigste, da MongoDB 3.2+ eine Join-Lösung namens $lookup implementiert hat. Ich dachte, ich würde sie hier einfügen, weil vielleicht nicht jeder bis zum Ende liest. stackoverflow.com/a/33511166/2593330

10 Stimmen

Richtig, $Nachschlag wurde in MongoDB 3.2 eingeführt. Einzelheiten finden Sie unter docs.mongodb.org/master/reference/operator/aggregation/lookup/

0 Stimmen

Konvertieren Sie eine beliebige Abfrage in Mongo und prüfen Sie die Antwort: stackoverflow.com/questions/68155715/

23voto

jarry jafery Punkte 888

Sie können zwei Sammlungen in Mongo verbinden, indem Sie Lookup verwenden, das in Version 3.2 angeboten wird. In Ihrem Fall würde die Abfrage lauten

db.comments.aggregate({
    $lookup:{
        from:"users",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

oder Sie können auch in Bezug auf die Benutzer beitreten, dann wird es eine kleine Änderung wie unten angegeben.

db.users.aggregate({
    $lookup:{
        from:"comments",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

Es funktioniert genauso wie die linke und rechte Verknüpfung in SQL.

19voto

grepit Punkte 18534

Wie andere darauf hingewiesen haben, versuchen Sie, eine relationale Datenbank aus keiner relationalen Datenbank zu erstellen, die Sie wirklich nicht tun wollen, aber wie auch immer, wenn Sie einen Fall haben, dass Sie dies tun müssen, hier ist eine Lösung, die Sie verwenden können. Wir führen zunächst eine foreach-Suche in der Sammlung A (oder in Ihrem Fall Benutzer) durch und erhalten dann jedes Element als Objekt. Dann verwenden wir die Objekteigenschaft (in Ihrem Fall uid), um in unserer zweiten Sammlung (in Ihrem Fall Kommentare) zu suchen, und wenn wir sie finden, haben wir eine Übereinstimmung und können sie ausdrucken oder etwas mit ihr machen. Ich hoffe, dies hilft Ihnen und viel Glück :)

db.users.find().forEach(
function (object) {
    var commonInBoth=db.comments.findOne({ "uid": object.uid} );
    if (commonInBoth != null) {
        printjson(commonInBoth) ;
        printjson(object) ;
    }else {
        // did not match so we don't care in this case
    }
});

0 Stimmen

Findet dies nicht das Element, das wir gerade in der Schleife haben?

17voto

antitoxic Punkte 3666

Hier ist ein Beispiel für eine "verbinden" * Schauspieler y Filme Sammlungen:

https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt

Es nutzt die .mapReduce() Methode

* beitreten - eine Alternative zum Join in dokumentenorientierten Datenbanken

22 Stimmen

-1, Dies ist KEINE Verbindung von Daten aus zwei Sammlungen. Es werden Daten aus einer einzigen Sammlung (Akteure) verwendet und die Daten umgedreht. So dass Dinge, die Schlüssel waren, jetzt Werte sind und Werte jetzt Schlüssel sind... muy anders als ein JOIN.

14 Stimmen

Das ist genau das, was Sie tun müssen, denn MongoDB ist nicht relational, sondern dokumentenorientiert. MapReduce ermöglicht es, mit Daten mit großer Leistung zu spielen (Sie können Cluster etc.... verwenden), aber auch für einfache Fälle, ist es sehr nützlich!

17voto

GoutamS Punkte 3287

$lookup (Aggregation)

Führt eine linke äußere Verknüpfung mit einer nicht gesharten Sammlung in derselben Datenbank durch, um Dokumente aus der "verknüpften" Sammlung zur Verarbeitung herauszufiltern. Zu jedem Eingabedokument fügt die $lookup-Stufe ein neues Array-Feld hinzu, dessen Elemente die übereinstimmenden Dokumente aus der "joined"-Sammlung sind. Die $lookup-Stufe übergibt diese umgestalteten Dokumente an die nächste Stufe. Die $lookup-Stufe hat die folgenden Syntaxen:

Gleichheitsspiel

Um eine Gleichheitsübereinstimmung zwischen einem Feld aus den Eingabedokumenten und einem Feld aus den Dokumenten der "joined"-Sammlung durchzuführen, hat die $lookup-Stufe die folgende Syntax:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

Der Vorgang würde der folgenden Pseudo-SQL-Anweisung entsprechen:

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
                               FROM <collection to join>
                               WHERE <pipeline> );

Mongo-URL

1 Stimmen

Sub-Abfrage ist völlig anders als join, wenn Ihre linke Seite Tabelle ist riesig, Sub-Abfrage bedeutet jede Zeile hat eine Abfrage selbst zu tun. es wird sehr langsam. join ist sehr schnell in Sql.

12voto

Snowburnt Punkte 5943

Das hängt davon ab, was Sie erreichen wollen.

Sie haben sie derzeit als normalisierte Datenbank eingerichtet, was in Ordnung ist, und die Art und Weise, wie Sie es tun, ist angemessen.

Es gibt jedoch auch andere Möglichkeiten, dies zu tun.

Sie könnten eine Sammlung von Beiträgen haben, die eingebettete Kommentare für jeden Beitrag mit Verweisen auf die Benutzer enthält, die Sie iterativ abfragen können, um sie zu erhalten. Sie könnten den Namen des Benutzers mit den Kommentaren speichern, Sie könnten sie alle in einem Dokument speichern.

Das Besondere an NoSQL ist, dass es für flexible Schemata und sehr schnelles Lesen und Schreiben ausgelegt ist. In einer typischen Big-Data-Farm ist die Datenbank der größte Engpass, man hat weniger Datenbank-Engines als Anwendungs- und Front-End-Server... sie sind teurer, aber leistungsfähiger, und auch der Festplattenspeicher ist vergleichsweise sehr günstig. Die Normalisierung beruht auf dem Konzept der Platzersparnis, hat aber den Preis, dass Ihre Datenbanken komplizierte Joins durchführen, die Integrität von Beziehungen überprüfen und kaskadierende Operationen durchführen müssen. All dies erspart den Entwicklern einiges an Kopfzerbrechen, wenn sie die Datenbank richtig konzipiert haben.

Wenn Sie bei NoSQL davon ausgehen, dass Redundanz und Speicherplatz aufgrund ihrer Kosten (sowohl in Bezug auf die für Aktualisierungen erforderliche Prozessorzeit als auch auf die Festplattenkosten für die Speicherung zusätzlicher Daten) keine Rolle spielen, ist die Denormalisierung kein Problem (bei eingebetteten Arrays, die Hunderttausende von Elementen umfassen, kann dies ein Leistungsproblem darstellen, aber in den meisten Fällen ist dies kein Problem). Außerdem werden Sie mehrere Anwendungs- und Front-End-Server für jeden Datenbank-Cluster haben. Lassen Sie diese die schwere Arbeit der Joins erledigen und überlassen Sie den Datenbankservern das Lesen und Schreiben.

TL;DR: Was Sie tun, ist in Ordnung, und es gibt andere Möglichkeiten, es zu tun. Schauen Sie sich die Datenmodellmuster der Mongodb-Dokumentation für einige großartige Beispiele an. http://docs.mongodb.org/manual/data-modeling/

9 Stimmen

"Die Normalisierung entspringt dem Konzept der Platzersparnis", was ich in Frage stelle. IMHO entspringt die Normalisierung dem Konzept der Vermeidung von Redundanz. Angenommen, Sie speichern den Namen eines Benutzers zusammen mit einem Blogpost. Was ist, wenn sie heiratet? In einem nicht normalisierten Modell müssen Sie sich durch alle Beiträge durcharbeiten und den Namen ändern. In einem normalisierten Modell ändern Sie normalerweise nur EINEN Datensatz.

0 Stimmen

@DanielKhan Redundanzvermeidung und Platzersparnis sind ähnliche Konzepte, aber nach erneuter Analyse stimme ich zu, dass Redundanz die Hauptursache für diesen Entwurf ist. Ich werde es umformulieren. Vielen Dank für den Hinweis.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X