sql >> Database >  >> NoSQL >> MongoDB

$unionWith - MongoDB's equivalent van UNION ALL

Als u bekend bent met SQL, kent u misschien de UNION clausule, die de resultaten van twee query's samenvoegt tot één resultaatset. In het bijzonder UNION ALL bevat duplicaten.

In MongoDB kunnen we de $unionWith . gebruiken aggregatiepijplijnfase om hetzelfde effect te bereiken dat UNION ALL produceert. De $unionWith stage voert een samenvoeging van twee collecties uit - het combineert pijplijnresultaten van twee collecties in een enkele resultaatset. En het bevat duplicaten.

Voorbeeld

Stel dat we twee collecties maken; een genaamd cats en een andere genaamd dogs . En we voegen de volgende documenten erin:

db.cats.insertMany([
    { _id: 1, name: "Fluffy", type: "Cat", weight: 5 },
    { _id: 2, name: "Scratch", type: "Cat", weight: 3 },
    { _id: 3, name: "Meow", type: "Cat", weight: 7 }
    ])

db.dogs.insertMany([
    { _id: 1, name: "Wag", type: "Dog", weight: 20 },
    { _id: 2, name: "Bark", type: "Dog", weight: 10 },
    { _id: 3, name: "Fluffy", type: "Dog", weight: 40 }
    ])

We kunnen nu een query uitvoeren op die collecties en de $unionWith . gebruiken stap om de resultaten van elke zoekopdracht te combineren.

Voorbeeld:

db.cats.aggregate( [
   { $set: { _id: "$_id" } },
   { $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "$_id" } } ] } },
   { $sort: { type: 1, weight: -1, name: 1 } }
] )

Resultaat:

{ "_id" : 3, "name" : "Meow", "type" : "Cat", "weight" : 7 }
{ "_id" : 1, "name" : "Fluffy", "type" : "Cat", "weight" : 5 }
{ "_id" : 2, "name" : "Scratch", "type" : "Cat", "weight" : 3 }
{ "_id" : 3, "name" : "Fluffy", "type" : "Dog", "weight" : 40 }
{ "_id" : 1, "name" : "Wag", "type" : "Dog", "weight" : 20 }
{ "_id" : 2, "name" : "Bark", "type" : "Dog", "weight" : 10 }

In dit voorbeeld heeft elk document een typeveld met ofwel cat of dog en zo is het vrij duidelijk welk document uit welke collectie komt.

Maar als de documenten het typeveld niet hadden, zou het moeilijker zijn om uit te zoeken waar de ene verzameling eindigt en de andere begint. In dit geval kunnen we een letterlijke tekenreeks gebruiken bij de $set podium om de collectienaam weer te geven.

Voorbeeld:

db.cats.aggregate( [
   { $set: { _id: "cat" } },
   { $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
   { $sort: { type: 1, weight: -1, name: 1 } }
] )

Resultaat:

{ "_id" : "cat", "name" : "Meow", "type" : "Cat", "weight" : 7 }
{ "_id" : "cat", "name" : "Fluffy", "type" : "Cat", "weight" : 5 }
{ "_id" : "cat", "name" : "Scratch", "type" : "Cat", "weight" : 3 }
{ "_id" : "dog", "name" : "Fluffy", "type" : "Dog", "weight" : 40 }
{ "_id" : "dog", "name" : "Wag", "type" : "Dog", "weight" : 20 }
{ "_id" : "dog", "name" : "Bark", "type" : "Dog", "weight" : 10 }

Sorteren over collecties

In de vorige voorbeelden waren de katten en de honden zo gesorteerd dat ze in twee verschillende groepen werden verdeeld; eerst katten, dan honden. Dit gebeurde voornamelijk omdat we sorteerden op het type veld eerst.

Maar we kunnen het op elk ander veld sorteren, wat ertoe kan leiden dat de katten en honden worden gecombineerd.

Voorbeeld:

db.cats.aggregate( [
   { $set: { _id: "cat" } },
   { $unionWith: { coll: "dogs", pipeline: [ { $set: { _id: "dog" } } ] } },
   { $sort: { name: 1 } }
] )

Resultaat:

{ "_id" : "dog", "name" : "Bark", "type" : "Dog", "weight" : 10 }
{ "_id" : "cat", "name" : "Fluffy", "type" : "Cat", "weight" : 5 }
{ "_id" : "dog", "name" : "Fluffy", "type" : "Dog", "weight" : 40 }
{ "_id" : "cat", "name" : "Meow", "type" : "Cat", "weight" : 7 }
{ "_id" : "cat", "name" : "Scratch", "type" : "Cat", "weight" : 3 }
{ "_id" : "dog", "name" : "Wag", "type" : "Dog", "weight" : 20 }

Projecties

U kunt het $project . gebruiken fase om aan te geven welke velden moeten worden doorgegeven aan de volgende fase in de pijplijn. Zo kunt u bijvoorbeeld het aantal velden dat door de zoekopdracht wordt geretourneerd, verminderen.

Voorbeeld:

db.cats.aggregate( [
   { $project: { name: 1, _id: 0 } },
   { $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} }
] )

Resultaat:

{ "name" : "Fluffy" }
{ "name" : "Scratch" }
{ "name" : "Meow" }
{ "name" : "Wag" }
{ "name" : "Bark" }
{ "name" : "Fluffy" }

Duplicaten verwijderen

U kunt de $group . gebruiken fase om overbodige duplicaten uit het resultaat te verwijderen.

De vorige zoekopdracht leverde bijvoorbeeld twee huisdieren op met de naam Fluffy. We kunnen een $group . toevoegen stap naar die zoekopdracht om het overtollige duplicaat te verwijderen, zodat er slechts één Fluffy wordt geretourneerd.

db.cats.aggregate( [
   { $project: { name: 1, _id: 0 } },
   { $unionWith: { coll: "dogs", pipeline: [ { $project: { name: 1, _id: 0 } } ]} },
   { $group: { _id: "$name" } }
] )

Resultaat:

{ "_id" : "Meow" }
{ "_id" : "Bark" }
{ "_id" : "Scratch" }
{ "_id" : "Wag" }
{ "_id" : "Fluffy" }

Deze keer wordt er maar één Fluffy geretourneerd.

Niet-overeenkomende kolommen

Een van de voordelen die MongoDB's $unionWith heeft meer dan SQL's UNION ALL is dat het kan worden gebruikt met niet-overeenkomende kolommen.

De SQL UNION clausule vereist dat:

  • Beide zoekopdrachten retourneren hetzelfde aantal kolommen
  • De kolommen in dezelfde volgorde
  • De overeenkomende kolommen moeten van een compatibel gegevenstype zijn

De MongoDB $unionWith stage legt deze beperkingen niet op.

Daarom zouden we $unionWith . kunnen gebruiken om zoiets als dit te doen:

db.cats.aggregate( [
   { $set: { _id: "$_id" } },
   { $unionWith: { coll: "employees", pipeline: [ { $set: { _id: "$_id" } } ] } },
   { $sort: { type: 1, salary: -1 } }
] )

Resultaat:

{ "_id" : 2, "name" : "Sarah", "salary" : 128000 }
{ "_id" : 5, "name" : "Beck", "salary" : 82000 }
{ "_id" : 4, "name" : "Chris", "salary" : 45000 }
{ "_id" : 3, "name" : "Fritz", "salary" : 25000 }
{ "_id" : 1, "name" : "Fluffy", "type" : "Cat", "weight" : 5 }
{ "_id" : 2, "name" : "Scratch", "type" : "Cat", "weight" : 3 }
{ "_id" : 3, "name" : "Meow", "type" : "Cat", "weight" : 7 }

In dit geval hebben we ons aangesloten bij de cats collectie met de employees verzameling. De employees collectie had niet dezelfde velden als de cats verzameling, maar dat is prima - het werkte nog steeds.


  1. Iets als een tag-cache en het opvragen om ze voor te stellen met Redis

  2. Hoe kan ik een object in MongoDB gedeeltelijk bijwerken, zodat het nieuwe object zal overlappen / samenvoegen met het bestaande?

  3. db.collection is geen functie bij gebruik van MongoClient v3.0

  4. Update ingebed object binnen array in array in MongoDB