it-swarm.com.de

Was ist der $ unwind Operator in MongoDB?

Dies ist mein erster Tag bei MongoDB.

Ich kann den Operator $unwind Nicht verstehen, möglicherweise weil Englisch nicht meine Muttersprache ist.

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

Ich glaube, der Projektbetreiber ist etwas, das ich verstehen kann (es ist wie SELECT, nicht wahr?). Aber dann gibt $unwind (Zitieren) ein Dokument für jedes Mitglied des abgewickelten Arrays in jedem Quelldokument zurück .

Ist das wie ein JOIN? Wenn ja, wie kann das Ergebnis von $project (Mit _id, author, title und tags) mit den tags Array?

NOTE : Ich habe das Beispiel der MongoDB-Website entnommen und kenne die Struktur des Arrays tags nicht. Ich denke, es ist eine einfache Anordnung von Tag-Namen.

69
gremo

Willkommen bei MongoDB!

Denken Sie daran, dass MongoDB einen "NoSQL" -Ansatz für die Datenspeicherung verwendet. Lassen Sie die Gedanken von Selects, Joins usw. aus Ihrem Kopf. Das Speichern Ihrer Daten erfolgt in Form von Dokumenten und Sammlungen, wodurch Sie die Daten dynamisch zu Ihren Speicherorten hinzufügen und von diesen abrufen können.

Um das Konzept hinter dem Parameter $ unwind zu verstehen, müssen Sie zunächst verstehen, was der Anwendungsfall, den Sie zitieren möchten, aussagt. Das Beispieldokument von mongodb.org lautet wie folgt:

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

Beachten Sie, dass Tags eine Reihe von drei Elementen sind, in diesem Fall "Spaß", "gut" und "Spaß".

Mit $ unwind können Sie ein Dokument für jedes Element abziehen und das resultierende Dokument zurückgeben. In einem klassischen Ansatz wäre dies gleichbedeutend mit "für jedes Element im Tag-Array ein Dokument mit nur diesem Element zurückgeben".

Somit ist das Ergebnis der folgenden Ausführung:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

würde die folgenden Dokumente zurückgeben:

{
     "result" : [
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "good"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             }
     ],
     "OK" : 1
}

Beachten Sie, dass sich im Ergebnis-Array nur das ändert, was im Tag-Wert zurückgegeben wird. Wenn Sie einen zusätzlichen Verweis benötigen, wie dies funktioniert, habe ich einen Link eingefügt hier . Hoffentlich hilft das und viel Glück bei Ihrem Streifzug durch eines der besten NoSQL-Systeme, auf die ich bisher gestoßen bin.

172
HGS Labs

$unwind dupliziert jedes Dokument in der Pipeline einmal pro Array-Element.

Wenn Ihre Eingabe-Pipeline also ein Artikeldokument mit zwei Elementen in tags enthält, {$unwind: '$tags'} würde die Pipeline in zwei Artikeldokumente umwandeln, die bis auf das Feld tags identisch sind. Im ersten Dokument würde tags das erste Element aus dem Array des ursprünglichen Dokuments enthalten, und im zweiten Dokument würde tags das zweite Element enthalten.

36
JohnnyHK

Lassen Sie es uns anhand eines Beispiels verstehen

So sieht das Unternehmensdokument aus:

original document

Mit dem $unwind können wir Dokumente als Eingabe mit einem Feld mit Array-Wert annehmen und Ausgabedokumente erstellen, sodass für jedes Element im Array ein Ausgabedokument vorhanden ist. Quelle

The $unwind stage

Kehren wir also zu den Beispielen unserer Unternehmen zurück und werfen Sie einen Blick auf die Verwendung von Abwicklungsstufen. Diese Abfrage:


db.companies.aggregate([
    { $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
    { $project: {
        _id: 0,
        name: 1,
        amount: "$funding_rounds.raised_amount",
        year: "$funding_rounds.funded_year"
    } }
])

erstellt Dokumente mit Arrays für Betrag und Jahr.

project output

Weil wir für jedes Element in der Reihe der Finanzierungsrunden auf den erhobenen Betrag und das finanzierte Jahr zugreifen. Um dies zu beheben, können wir eine Abwicklungsphase vor unserer Projektphase in diese Aggregationspipeline aufnehmen und dies parametrisieren, indem wir sagen, dass wir das Array der Finanzierungsrunden unwind möchten:


db.companies.aggregate([
    { $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
    { $unwind: "$funding_rounds" },
    { $project: {
        _id: 0,
        name: 1,
        amount: "$funding_rounds.raised_amount",
        year: "$funding_rounds.funded_year"
    } }
])

unwind has the effect of outputting to the next stage more documents than it receives as input

Wenn wir uns das Array funding_rounds ansehen, wissen wir, dass es für jedes funding_rounds ein raised_amount und ein funded_year Feld gibt. Also wird unwind für jedes der Dokumente, die Elemente des Arrays funding_rounds sind, ein Ausgabedokument erzeugen. In diesem Beispiel sind unsere Werte strings. Unabhängig vom Wertetyp für die Elemente in einem Array erstellt unwind für jeden dieser Werte ein Ausgabedokument, sodass das betreffende Feld nur dieses Element enthält. Im Fall von funding_rounds ist dieses Element eines dieser Dokumente als Wert für funding_rounds für jedes Dokument, das an unsere Stufe project weitergeleitet wird. Das Ergebnis ist dann, dass wir jetzt ein amount und ein year erhalten. Eine für jede Finanzierungsrunde für jedes Unternehmen in unserer Sammlung. Dies bedeutet, dass unser Match viele Unternehmensdokumente hervorgebracht hat und jedes dieser Unternehmensdokumente zu vielen Dokumenten führt. Eine für jede Finanzierungsrunde in jedem Unternehmensdokument. unwind führt diese Operation unter Verwendung der Dokumente aus, die ihm von der Stufe match übergeben wurden. Und alle diese Dokumente für jedes Unternehmen werden dann an die Stufe project übergeben.

unwind output

Alle Dokumente, bei denen der Geldgeber Greylock war (wie im Abfragebeispiel), werden in eine Anzahl von Dokumenten aufgeteilt, die der Anzahl der Finanzierungsrunden für jedes Unternehmen entspricht, das mit dem übereinstimmt filter $match: {"funding_rounds.investments.financial_org.permalink": "greylock" }. Und jedes dieser resultierenden Dokumente wird dann an unser project weitergeleitet. Jetzt erstellt unwind für jedes Dokument, das es als Eingabe erhält, eine exakte Kopie. Alle Felder haben den gleichen Schlüssel und Wert, mit einer Ausnahme. Das heißt, das Feld funding_rounds ist kein Array von funding_rounds Dokumenten, sondern hat einen Wert, der ein einzelnes Dokument ist Dies ist eine individuelle Finanzierungsrunde. Ein Unternehmen mit 4 Finanzierungsrunden führt also dazu, dass unwind 4 Dokumente erstellt. Wobei jedes Feld eine exakte Kopie ist, mit Ausnahme des funding_rounds -Felds, das kein Array für jede dieser Kopien darstellt, sondern ein einzelnes Element aus dem funding_rounds -Array aus dem Firmendokument, das unwind gerade verarbeitet. Daher bewirkt unwind, dass mehr Dokumente in die nächste Stufe ausgegeben werden, als als Eingaben eingehen. Dies bedeutet, dass unsere project -Stufe jetzt ein funding_rounds -Feld erhält, das wiederum kein Array ist, sondern ein verschachteltes Dokument mit einem raised_amount und ein funded_year Feld. Daher erhält project für jedes Unternehmen mehrere Dokumente match, die den Filter aktivieren, und kann daher jedes der Dokumente einzeln verarbeiten und für jedes einen individuellen Betrag und ein Jahr identifizieren Finanzierungsrunde für jedes Unternehmen .

13
student

Gemäß der offiziellen Dokumentation von Mongodb:

$ unwind Dekonstruiert ein Arrayfeld aus den Eingabedokumenten, um ein Dokument für jedes Element auszugeben. Jedes Ausgabedokument ist das Eingabedokument, wobei der Wert des Arrayfelds durch das Element ersetzt wird.

Erklärung anhand eines einfachen Beispiels:

Ein Sammlungsbestand enthält die folgenden Dokumente:

{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }

Die folgenden Operationen $ unwind sind äquivalent und geben ein Dokument für jedes Element im Feld sizes zurück. Wenn das Größenfeld nicht in ein Array aufgelöst wird, aber nicht fehlt, null oder ein leeres Array, behandelt $ unwind den Nicht-Array-Operanden als einzelnes Elementarray.

db.inventory.aggregate( [ { $unwind: "$sizes" } ] )

oder

db.inventory.aggregate( [ { $unwind: { path: "$sizes" } } ] 

Über Abfrage Ausgabe:

{ "_id" : 1, "item" : "ABC", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "sizes" : "L" }
{ "_id" : 3, "item" : "IJK", "sizes" : "M" }

Warum wird es benötigt?

$ unwind ist sehr nützlich, wenn Sie eine Aggregation durchführen. Es zerlegt komplexe/verschachtelte Dokumente in einfache Dokumente, bevor verschiedene Vorgänge wie Sortieren, Suchen usw. ausgeführt werden.

Um mehr über $ unwind zu erfahren:

https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

Um mehr über die Aggregation zu erfahren:

https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

2
Amitesh

Lassen Sie mich dies auf eine Art und Weise erklären, die mit RDBMS zusammenhängt. Dies ist die Aussage:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

auf das Dokument/den Datensatz anwenden:

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

Das $ project/Select gibt diese Felder/Spalten einfach als zurück

[~ # ~] Wählen Sie [~ # ~] Autor, Titel, Tags [~ # ~] aus [ ~ # ~] Artikel

Als nächstes kommt der lustige Teil von Mongo, betrachten Sie dieses Array tags : [ "fun" , "good" , "fun" ] als eine andere verwandte Tabelle (kann keine Nachschlag-/Referenztabelle sein, da die Werte einige Duplizierungen aufweisen) mit dem Namen "tags". Denken Sie daran, dass SELECT im Allgemeinen vertikale Dinge erzeugt, also wickeln Sie die "Tags" ab, um () vertikal in die Tabelle "Tags" aufzuteilen.

Das Endergebnis von $ project + $ unwind: enter image description here

Übersetzen Sie die Ausgabe in JSON:

{ "author": "bob", "title": "this is my title", "tags": "fun"},
{ "author": "bob", "title": "this is my title", "tags": "good"},
{ "author": "bob", "title": "this is my title", "tags": "fun"}

Da Mongo nicht angewiesen wurde, das Feld "_id" wegzulassen, wird es automatisch hinzugefügt.

Der Schlüssel besteht darin, die Aggregation tabellenartig zu gestalten.

1
Jeb50

betrachten Sie das folgende Beispiel, um diese Daten in einer Sammlung zu verstehen

{
        "_id" : 1,
        "shirt" : "Half Sleeve",
        "sizes" : [
                "medium",
                "XL",
                "free"
        ]
}

Abfrage - db.test1.aggregate ([{$ unwind: "$ sizes"}]);

ausgabe

{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }
0
Pravin