MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

$unionWith – Equivalente di MongoDB di UNION ALL

Se hai familiarità con SQL, potresti conoscere UNION clausola, che concatena i risultati di due query in un unico set di risultati. In particolare, UNION ALL include duplicati.

In MongoDB, possiamo usare $unionWith fase della pipeline di aggregazione per ottenere lo stesso effetto di UNION ALL produce. Il $unionWith stage esegue un'unione di due raccolte:combina i risultati della pipeline di due raccolte in un unico set di risultati. E include duplicati.

Esempio

Supponiamo di creare due raccolte; uno chiamato cats e un altro chiamato dogs . E vi inseriamo i seguenti documenti:

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

Ora possiamo eseguire una query su tali raccolte e utilizzare $unionWith fase per combinare i risultati di ogni query.

Esempio:

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

Risultato:

{ "_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 questo esempio, ogni documento ha un campo tipo con cat o dog e quindi è abbastanza evidente quale documento proviene da quale collezione.

Ma se i documenti non avessero il campo tipo, sarebbe più difficile capire dove finisce una raccolta e inizia un'altra. In questo caso, possiamo usare una stringa letterale in $set fase per rappresentare il nome della collezione.

Esempio:

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

Risultato:

{ "_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 }

Ordinamento tra raccolte

Negli esempi precedenti, i gatti ei cani sono stati ordinati in modo da separarli in due gruppi distinti; prima i gatti, poi i cani. Ciò è accaduto principalmente perché abbiamo ordinato il type prima il campo.

Ma possiamo ordinarlo su qualsiasi altro campo, il che potrebbe comportare la combinazione di cani e gatti.

Esempio:

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

Risultato:

{ "_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 }

Proiezioni

Puoi usare il $project fase per specificare quali campi devono essere passati alla fase successiva della pipeline. Ad esempio, puoi quindi ridurre il numero di campi restituiti dalla query.

Esempio:

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

Risultato:

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

Rimuovi duplicati

Puoi usare il $group fase per eliminare i duplicati ridondanti dal risultato.

Ad esempio, la query precedente ha restituito due animali chiamati Fluffy. Possiamo aggiungere un $group fase a quella query per eliminare il duplicato ridondante, in modo che venga restituito un solo Fluffy.

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

Risultato:

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

Questa volta viene restituito un solo Fluffy.

Colonne non corrispondenti

Uno dei vantaggi di $unionWith di MongoDB ha superato UNION ALL di SQL è che può essere utilizzato con colonne non corrispondenti.

L'SQL UNION clausola richiede che:

  • Entrambe le query restituiscono lo stesso numero di colonne
  • Le colonne nello stesso ordine
  • Le colonne corrispondenti devono essere di un tipo di dati compatibile

Il $unionWith di MongoDB stage non impone queste limitazioni.

Pertanto, potremmo usare $unionWith per fare qualcosa del genere:

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

Risultato:

{ "_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 questo caso, ci siamo uniti ai cats raccolta con i employees collezione. I employees la raccolta non aveva gli stessi campi di cats collezione, ma va bene:ha funzionato ancora.