sql >> Databasteknik >  >> NoSQL >> MongoDB

$unionWith – MongoDB:s motsvarighet till UNION ALL

Om du är bekant med SQL kanske du känner till UNION klausul, som sammanfogar resultaten av två frågor till en enda resultatuppsättning. I synnerhet UNION ALL inkluderar dubbletter.

I MongoDB kan vi använda $unionWith aggregeringspipeline för att uppnå samma effekt som UNION ALL producerar. $unionWith stage genomför en sammanslutning av två samlingar – den kombinerar pipelineresultat från två samlingar till en enda resultatuppsättning. Och det inkluderar dubbletter.

Exempel

Anta att vi skapar två samlingar; en som heter cats och en annan som heter dogs . Och vi infogar följande dokument i dem:

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 }
    ]) 

Vi kan nu köra en sökning mot dessa samlingar och använda $unionWith steg för att kombinera resultaten av varje fråga.

Exempel:

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

Resultat:

{ "_id" :3, "name" :"Mjau", "type" :"Katt", "vikt" :7 }{ "_id" :1, "name" :"Fluffig", "typ" :"Cat", "weight" :5 }{ "_id" :2, "name" :"Scratch", "type" :"Cat", "weight" :3 }{ "_id" :3, "name" :"Fluffig", "type" :"Hund", "vikt" :40 }{ "_id" :1, "name" :"Wag", "type" :"Hund", "vikt" :20 }{ " _id" :2, "name" :"Skall", "type" :"Hund", "vikt" :10 }

I det här exemplet har varje dokument ett typfält med antingen cat eller dog och så det är ganska uppenbart vilket dokument som kommer från vilken samling.

Men om dokumenten inte hade typfältet, skulle det vara svårare att räkna ut var en insamling slutar och en annan börjar. I det här fallet kan vi använda en bokstavlig sträng vid $set steg för att representera samlingens namn.

Exempel:

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

Resultat:

{ "_id" :"cat", "name" :"Mjau", "type" :"Katt", "vikt" :7 }{ "_id" :"katt", "name" :"Fluffig" , "type" :"Katt", "vikt" :5 }{ "_id" :"katt", "namn" :"Scratch", "type" :"Katt", "vikt" :3 }{ "_id" :"hund", "name" :"Fluffig", "type" :"Hund", "vikt" :40 }{ "_id" :"hund", "name" :"Wag", "type" :"Hund ", "weight" :20 }{ "_id" :"dog", "name" :"Bark", "type" :"Hund", "weight" :10 }

Sortera över samlingar

I de tidigare exemplen sorterades katterna och hundarna på ett sätt som separerade dem i två distinkta grupper; först katter, sedan hundar. Detta hände främst för att vi sorterade på type fältet först.

Men vi kan sortera det på vilket annat fält som helst, vilket kan resultera i att katter och hundar kombineras.

Exempel:

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

Resultat:

{ "_id" :"hund", "name" :"Skall", "type" :"Hund", "vikt" :10 }{ "_id" :"katt", "name" :"Fluffig" , "type" :"Katt", "vikt" :5 }{ "_id" :"hund", "name" :"Fluffig", "type" :"Hund", "vikt" :40 }{ "_id" :"cat", "name" :"Mjau", "type" :"Katt", "vikt" :7 }{ "_id" :"katt", "name" :"Krata", "typ" :"Katt ", "weight" :3 }{ "_id" :"dog", "name" :"Wag", "type" :"Hund", "weight" :20 }

Projektioner

Du kan använda $project steg för att specificera vilka fält som ska skickas vidare till nästa steg i pipelinen. Till exempel kan du därför minska antalet fält som returneras av frågan.

Exempel:

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

Resultat:

{ "name" :"Fluffig" }{ "name" :"Scratch" }{ "name" :"Mjau" }{ "name" :"Wag" }{ "name" :"Bark" }{ " name" :"Fluffig" }

Ta bort dubbletter

Du kan använda $group steg för att eliminera redundanta dubbletter från resultatet.

Till exempel returnerade den tidigare frågan två husdjur som heter Fluffy. Vi kan lägga till en $group steg till den frågan för att eliminera den redundanta dubbletten, så att bara en Fluffy returneras.

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

Resultat:

{ "_id" :"Mjau" }{ "_id" :"Bark" }{ "_id" :"Scratch" }{ "_id" :"Wag" }{ "_id" :"Fluffig" } 

Den här gången returneras endast en Fluffy.

Icke-matchande kolumner

En av fördelarna med MongoDB:s $unionWith har över SQL:s UNION ALL är att den kan användas med icke-matchande kolumner.

SQL UNION klausul kräver att:

  • Båda frågorna returnerar samma antal kolumner
  • Kolumnerna i samma ordning
  • De matchande kolumnerna måste vara av en kompatibel datatyp

MongoDB $unionWith steg inte inför dessa begränsningar.

Därför kan vi använda $unionWith att göra något så här:

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

Resultat:

{ "_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" :"Fluffig ", "type" :"Katt", "vikt" :5 }{ "_id" :2, "name" :"Scratch", "type" :"Katt", "vikt" :3 }{ "_id" :3, "name" :"Mjau", "typ" :"Katt", "vikt" :7 }

I det här fallet gick vi med i cats insamling med employees samling. employees samlingen hade inte samma fält som cats samling, men det är bra – det fungerade fortfarande.


  1. Hur man byter namn på flera nycklar i Redis

  2. Redis är konfigurerat för att spara RDB-ögonblicksbilder, men det kan för närvarande inte finnas kvar på disken - Ubuntu Server

  3. Mongo Change Streams körs flera gånger (typ):Nodapp som kör flera instanser

  4. Redis benchmarking för hget- och hset-kommandon