Unter MongoDB ist es möglich, Informationen in Form von mehr oder weniger komplexen Objekten zu speichern. Es kann vorkommen, dass man mehrere Felder aus einem Teilobjekt einer Sammlung vergleichen will.
In unserem Beispiel werden wir eine Produktkollektion verwenden, in der das Preisfeld verschiedene Preise (Kauf, HT, TTC-Verkauf, …) definieren wird.
Struktur der Sammlung
Das Preisfeld enthält hier 2 Werte, die wir vergleichen werden:
- Verkaufspreis ohne MwSt.,
- der Verkaufspreis inkl.
=> Daten im Originalformat
Wie kann man eine Projektion mit Filter durchführen?
Da diese Daten komplex sind, ist es nicht möglich, die Werte direkt miteinander zu vergleichen. Dazu ist es notwendig, eine Projektion zu durchlaufen.
Abfrage
[ { '$project': { 'prix_vte': { '$filter': { 'input': '$prix', 'as': 'list', 'cond': { '$eq": [ $list.id, prix_vente_ht_eur. ] } } }, 'prix_vte_ttc': { '$filter': { 'input': '$prix', 'as': 'list', 'cond': { '$eq": [ $list.id, prix_vente_ttc_eur. ] } } } } }, { '$match": { '$expr': { '$gte": [ '$prix_vte.wert', '$prix_vte_ttc.wert' ] } } } ]
1 Datenprojektion
Zuerst führen wir eine Projektion "$project" durch, um informationen Namen zu filtern und zu nennen, um sie in unserem Filter "$match" zu verwenden.
In'prix_vte'beziehen wir das Filterergebnis '$filter' auf das Preisfeld mit dem Wert 'id' = 'prix_vente_ht_eur'
Dasselbe gilt für'prix_vte_ttc'das Ergebnis des Filters '$filter' auf das Preisfeld mit dem Wert 'id' = 'prix_vente_ttc_eur'.
=> Daten im projektierten Format
2 Vergleich der Werte
Dann bleibt der letzte Schritt, unsere 2 Werte mit einem '$match' als Ausdruck zu vergleichen oder zu testen, ob '$prix_vte' >= '$prix_vte_ttc'
'$match": { '$expr': { '$gte": [ '$prix_vte.wert', '$prix_vte_ttc.wert' ] } }
3 Wiederherstellung der Ergebnisse
Am Ende bleiben nur noch die Aufnahmen, die den Test bestehen.Diese Aufzeichnungen sind in dem format, das zuvor bei der Projektion festgelegt wurde.
Wie kann ich die Anfrage ausführen?
Es genügt, die Abfrage mit Hilfe der Funktion 'Aggregate' auszuführen, indem Sie folgendermaßen vorgehen:
db.Erzeugnis.Aggregate [{ ‘$project’: { ‘prix_vte’: { …… }] ()
Andere Fälle
In einfacheren Fällen, wenn unsere 2 Felder verglichen sind nur Felder, gibt es mehrere Möglichkeiten, um 2 Felder zu vergleichen.
Hier keine komplexen Daten, nur 2 Felder vom Typ 'doppel'
Das Äquivalent der MySQL-Abfrage würde folgendes geben:
SELECT * FROM MaCollection
Feld1 > Feld2
Verwenden Sie $where
Sie können ein '$where' verwenden. Bitte beachten Sie einfach, dass dies langsam sein wird (denn Javascript-Code muss auf jeder Registrierung ausgeführt werden), also denken Sie daran, indexe richtig zu erstellen.
db.MaCollection.find { $where: function () {return this.champ1 > this.champ2 } } }
Oder einfach:
db.MaCollection.find ( $where: "this.champ1 > this.champ2"});
Wenn Ihre Anfrage nur aus einem $where können Sie sogar nur den Javascript-Code übermitteln.
db.MaCollection.find ( "this.champ1 > this.champ2");
Der Ausdruck $expr
Seit MongoDB 3.6 ist es möglich, die Ggregationsfunktionen in einer normalen 'find' Abfrage zu verwenden.
db.MaCollection.find{ $expr:{$gt}} ["$champ1", "$champ2"]
Oder im Antrag auf Verdauung
db.MaCollection.Aggregate$match:{$expr:$gt} ["$champ1", "$champ2"]
Die Projektionen bis
Es kommt manchmal vor, dass viele Aufnahmen bei einer Suche verarbeitet werden müssen. Um die Bearbeitungsgeschwindigkeit erheblich zu beschleunigen, ist es manchmal notwendig, Projektionen zu heranziehen.
Wir sind hier für den Fall, dass unsere Sammlung mehrere Tausend Aufnahmen mit etwa 30 Feldern enthält
Test mit einem klassischen 'find'
Ansprechzeit von 4.41s
db.MaCollection.find ( $where: "this.champ1 > this.champ2"});
Test mit einem '$project'
Ansprechzeit von 185ms
db.MaCollection.aggregate ([
{
'$project': {
"isGreater": [ "$champ1", "$champ2" ] {$cmp},
Feld 1,
'Feld2': 1
}
},
{
'$match': {'isGreater': 1 }
}
]))
Durch die Projektion holen wir nur unsere Felder 1 und 2 zurück, sowie das Ergebnis des Vergleichs von Champ1 und Champ2, den wir in das Feld'isGreater'
setzen, das wir testen.