In jedem Unternehmen sind Daten dein größtes Kapital. Durch die Analyse von Daten kannst du Entscheidungen über Kundentrends und Verhaltensvorhersagen treffen. Das steigert die Rentabilität deines Unternehmens und verbessert die Entscheidungsfindung.

Ohne Datenbanksoftware wäre eine einfache Aufgabe wie die Ermittlung des Durchschnitts aller Werte in einem System voller Datensätze sehr mühsam. Zum Glück haben Datenbanken die Analyse von Daten mit Funktionen und Operatoren einfacher und schneller gemacht.

Dieser Artikel beleuchtet die Operatoren, die in der Datenbanksoftware MongoDB verwendet werden.

Was sind MongoDB-Operatoren?

MongoDB ist eine NoSQL-Datenbanksoftware, die dokumentenorientierte Informationen verwaltet.

Eine der wichtigsten Eigenschaften von MongoDB ist ihre Geschwindigkeit. Um Abfragen schneller zu beantworten, kann MongoDB Operatoren verwenden, um bestimmte Funktionen auszuführen.

Operatoren sind spezielle Symbole, die Compilern helfen, mathematische oder logische Aufgaben auszuführen. MongoDB bietet mehrere Arten von Operatoren, um mit der Datenbank zu interagieren.

MongoDB-Operator-Typen

Es gibt neun Arten von Operatoren, die jeweils nach ihrer Funktion benannt sind. Logische Operatoren zum Beispiel verwenden logische Operationen. Um sie auszuführen, musst du ein bestimmtes Schlüsselwort verwenden und die Syntax beachten. Sie sind jedoch ziemlich einfach zu verstehen!

Am Ende dieses Artikels wirst du die Grundlagen der einzelnen Operatoren und ihrer Funktionen kennenlernen.

Logische Operatoren

Logische Operatoren werden oft verwendet, um Daten nach bestimmten Bedingungen zu filtern. Sie ermöglichen auch die Auswertung vieler Bedingungen, auf die wir noch näher eingehen werden.

Im Folgenden findest du einige logische Operatoren, die du verwenden kannst:

$und

Eine „und“-Bedingung führt eine logische „und“-Operation mit einem Array aus zwei oder mehr Ausdrücken durch. Sie wählt die Dokumente aus, bei denen alle Bedingungen der Ausdrücke erfüllt sind.

Dies ist die Standardsyntax für den Ausdruck $and:

{ $and: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }
db.inventory.find( { $and: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

$oder

Eine „oder“-Bedingung führt eine logische „oder“-Operation an einem Array aus zwei oder mehr Ausdrücken durch. Sie wählt die Dokumente aus, bei denen mindestens einer der Ausdrücke wahr ist.

Dies ist die Standardsyntax für den Ausdruck $or:

{ $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }.

Wenn wir zum Beispiel Dokumente auswählen wollen, bei denen der Preis $10 oder die Menge weniger als 15 beträgt, können wir die folgende Abfrage eingeben:

db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

Wir müssen den Ausdruck nicht auf zwei Kriterien beschränken – wir können weitere hinzufügen. Die folgende Abfrage wählt zum Beispiel die Dokumente aus, bei denen der Preis gleich $10 ist, die Menge unter 15 liegt oder das Tag stationär ist:

db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 }, { tag: "stationary" }] } )

Wenn diese Klauseln ausgeführt werden, führt MongoDB entweder einen Collection Scan oder einen Index Scan durch. Wenn alle Indizes die Klauseln unterstützen, verwendet MongoDB Indizes, um einen $or Ausdruck zu überprüfen. Andernfalls verwendet es stattdessen einen Collection Scan.

Wenn du jedoch die Kriterien im selben Feld prüfen willst, solltest du den $in Operator statt des $or Operators verwenden. Wenn du zum Beispiel eine Sammlung von Dokumenten suchst, bei denen die Menge entweder 20 oder 50 beträgt, musst du stattdessen die folgende $in Abfrage ausführen:

db.inventory.find ( { quantity: { $in: [20, 50] } } )

Auf den $in Operator gehen wir später noch genauer ein.

$nor

Dieser Operator führt eine logische „nor“-Operation auf einem Array mit einem oder mehreren Ausdrücken durch. Anschließend wählt er die Dokumente aus, die die Abfrageausdrücke nicht erfüllen. Einfacher ausgedrückt: Er macht das Gegenteil der $or Bedingung.

Dies ist die allgemeine Syntax:

{ $nor: [ { <expression1> }, { <expression2> }, ...  { <expressionN> } ] }

Betrachten wir die folgende Abfrage:

db.inventory.find( { $nor: [ { price: 3.99 }, { sale: true } ]  } )

Diese Abfrage wählt die Dokumente aus, die enthalten:

  • ein Preisfeldwert ungleich $3,99 und ein Verkaufswert ungleich true; oder
  • ein Preisfeld mit einem Wert ungleich $3,99 und ein leeres oder fehlendes Verkaufsfeld; oder
  • kein Preisfeld und ein Verkaufsfeld, das nicht gleich wahr ist; oder
  • weder ein Preisfeld noch ein Verkaufsfeld ausgefüllt oder vorhanden ist.

$nicht

Dieser Operator führt eine logische „Nicht“-Operation auf einem Array für den angegebenen Ausdruck durch. Er wählt dann die Dokumente aus, die nicht mit den Abfrageausdrücken übereinstimmen. Dazu gehören auch die Dokumente, die das Feld nicht enthalten.

Dies ist die allgemeine Syntax:

{ field: { $not: { <operator-expression> } } }

Nimm zum Beispiel die folgende Abfrage:

db.inventory.find( { price: { $not: { $lt: 3.99 } } } )

Diese Abfrage würde die Dokumente auswählen, die Folgendes enthalten:

  • ein Preisfeld, dessen Wert größer oder gleich $3,99 ist; und
  • ein Preisfeld, dass nicht ausgefüllt ist oder nicht existiert.

Vergleichsoperatoren

Vergleichsoperatoren können verwendet werden, um Werte in einem oder mehreren Dokumenten zu vergleichen.

Im Folgenden findest du ein Codebeispiel für eine einfache Bestandserfassung für einen Supermarkt:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] },
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] },
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] },
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] },
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] },
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Anhand dieses Beispiels werden wir im Folgenden die einzelnen Vergleichsoperatoren näher erläutern.

Gleich ($eq)

Dieser Operator vergleicht Werte, die gleich dem angegebenen Wert sind:

{ <field>: { $eq: <value> } }

Wenn wir zum Beispiel ein bestimmtes Dokument aus der Bestandssammlung abrufen wollen, das genau den Mengenwert „20“ hat, geben wir den folgenden Befehl ein:

db.inventory.find( { qty: { $eq: 20 } } )

Die Abfrage würde das Folgende zurückgeben:

{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }, 
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Größer als ($gt)

Dieser Operator passt, wenn die Werte größer sind als der angegebene Wert:

{ field: { $gt: value } }

In diesem Beispiel finden wir die Dokumente, bei denen die Menge größer als 15 ist:

db.inventory.find({"qty": { $gt: 15}})

Die Abfrage würde Folgendes ergeben:

{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Kleiner als ($lt)

Dieser Operator passt, wenn die Werte kleiner sind als der angegebene Wert:

{ field: { $lt: value } }

Lass uns die Dokumente mit einer Anzahl von weniger als 25 finden:

db.inventory.find({"qty": { $lt: 25}})

Die Abfrage würde Folgendes ergeben:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Größer oder gleich ($gte)

Dieser Operator passt, wenn die Werte größer oder gleich dem angegebenen Wert sind:

{ field: { $gte: value } }

In diesem Beispiel suchen wir die Dokumente, bei denen die Menge größer oder gleich 25 ist:

db.inventory.find({"qty": { $gte: 25}})

Diese Abfrage würde das Folgende zurückgeben:

{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }

Kleiner oder gleich ($lte)

Dieser Operator passt nur, wenn die Werte kleiner oder gleich dem angegebenen Wert sind:

{ field: { $lte: value } }

Suchen wir die Dokumente, deren Anzahl kleiner oder gleich 25 ist.

db.inventory.find({"qty": { $lte: 25}})

Wir können erwarten, dass diese Abfrage das Folgende zurückgibt:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

In ($in)

Dieser Operator gibt die Dokumente zurück, die mit den angegebenen Werten übereinstimmen:

{ field: { $in: [<value1>, <value2>, ... <valueN> ] } }

Der Wert eines Feldes entspricht einem beliebigen Wert in dem angegebenen Array. Um zum Beispiel die Dokumente mit den Werten „30“ und „15“ in der Inventarsammlung abzurufen, würdest du so vorgehen:

db.inventory.find({ "qty": { $in: [30, 15]}})

Die Ausgabe würde lauten:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }

Nicht in ($nin)

Dieser Operator gibt die Dokumente zurück, die nicht mit den angegebenen Werten übereinstimmen. Hier ist die grundlegende Syntax des $nin Operators:

{ field: { $nin: [ <value1>, <value2> ... <valueN> ]

$nin wählt die Dokumente aus, bei denen:

  • der Feldwert nicht im angegebenen Array enthalten ist; oder
  • das Feld nicht existiert.

Wenn das Feld Arrays enthält, wählt es Arrays aus, in denen kein Element aus dem Wertebereich vorhanden ist. Wir wollen zum Beispiel die Dokumente auswählen, bei denen die Menge nicht gleich 20 oder 15 ist.

Außerdem werden auch Dokumente ausgewählt, die kein Mengenfeld enthalten:

db.inventory.find({ "qty": { $nin: [ 20, 15 ]}})

Die Ausgabe würde lauten:

{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Nicht gleich ($ne)

Der $ne Operator gibt die Dokumente zurück, bei denen der angegebene Wert nicht gleich ist:

{ $ne: value } }

Nehmen wir an, wir wollen alle Dokumente auswählen, bei denen die Menge nicht gleich 20 ist:

db.inventory.find( { qty: { $ne: 20 } } )

Die Ausgabe würde lauten:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Anhand der obigen Ausgabe können wir sehen, dass die Abfrage Dokumente auswählt, die kein Mengenfeld haben.

Element-Operatoren

Mit den Elementabfrageoperatoren können Dokumente anhand der Felder des Dokuments identifiziert werden. Die Elementoperatoren bestehen aus $exist und $type.

$exists

Dieser Operator findet Dokumente, die ein bestimmtes Feld haben. Dieser Operator hat einen booleschen Wert, der entweder true oder false sein kann.

Wenn der Wert true ist, werden alle Dokumente gefunden, die das Feld enthalten, einschließlich der Dokumente, in denen der Feldwert Null ist. Wenn <boolean> false ist, gibt die Abfrage nur die Dokumente zurück, die das Feld nicht enthalten.

Hier ist die Standardsyntax:

{ field: { $exists: <boolean> } } )

Nehmen wir ein Beispiel, in dem wir eine Sammlung von Daten für ein Array mit dem Namen „bagofmarbles“ haben, in dem jede Tüte Murmeln in verschiedenen Farben enthält:

{ red: 5, green: 5, blue: null }
{ red: 3, green: null, blue: 8 }
{ red: null, green: 3, blue: 9 }
{ red: 1, green: 2, blue: 3 }
{ red: 2, blue: 5 }
{ red: 3, green: 2 }
{ red: 4 }
{ green: 2, blue: 4 }
{ green: 2 }
{ blue: 6 }

Nehmen wir an, wir wollen eine Abfrage, die nur die Beutel zurückgibt, in denen sich rote Murmeln befinden. Das bedeutet, dass wir den booleschen Wert als true eingeben müssen. Schauen wir uns das mal an:

db.bagofmarbles.find( { red: { $exists: true } } )

Die Ergebnisse würden aus den Dokumenten bestehen, die das Feld „rot“ enthalten, auch wenn der Wert null wäre. Allerdings würden sie nicht aus den Dokumenten bestehen, in denen das Feld „rot“ gar nicht existiert:

{ red: 5, green: 5, blue: null }
{ red: 3, green: null, blue: 8 }
{ red: null, green: 3, blue: 9 }
{ red: 1, green: 2, blue: 3 }
{ red: 2, blue: 5 }
{ red: 3, green: 2 }
{ red: 4 }

Wenn wir nur die Taschen haben wollen, in denen das Feld „rote Murmeln“ gar nicht vorkommt, können wir die folgende Abfrage eingeben:

db.bagofmarbles.find( { red: { $exists: false} )

Die Ergebnisse würden aus den Dokumenten bestehen, die das Feld „rot“ nicht enthalten:

{ green: 2, blue: 4 }
{ green: 2 }
{ blue: 6 }

$Typ

Dieser Operator gleicht Dokumente nach dem angegebenen Feldtyp ab. Dies ist nützlich, wenn du sehr unstrukturierte Daten hast oder wenn die Datentypen nicht vorhersehbar sind. Diese Feldtypen werden als BSON-Typen angegeben und können entweder durch eine Typnummer oder einen Alias definiert werden.

Dies ist die allgemeine Syntax für $type:

{ field: { $type: <BSON type> } }

Nehmen wir an, wir haben ein Adressbuch mit den folgenden Dokumenten:

db={
  addressBook: [
    {
      "_id": 1,
      address: "2100 Jupiter Spot",
      zipCode: "9036325"
    },
    {
      "_id": 2,
      address: "25 Moon Place",
      zipCode: 26237
    },
    {
      "_id": 3,
      address: "2324 Neptune Ring",
      zipCode: NumberLong(77622222)
    },
    {
      "_id": 4,
      address: "33 Saturns Moon",
      zipCode: NumberInt(117)
    },
    {
      "_id": 5,
      address: "1044 Venus Lane",
      zipCode: [
        "99883637232",
        "73488976234"
      ]
    }
  ]
}

In den oben genannten Dokumenten gibt es für die Postleitzahl verschiedene Datentypen. Dazu gehören Long-, Double-, Integer- und String-Werte.

Wenn wir nur die Dokumente haben wollen, die einen bestimmten Datentyp als Postleitzahl haben – nehmen wir in diesem Fall String – müssen wir die folgende Abfrage in den Compiler eingeben:

db.addressBook.find({
  "zipCode": {
    $type: "string"
  }
})

Dies würde die folgenden Dokumente zurückgeben:

[
  {
    "_id": 1,
    "address": "2100 Jupiter Spot",
    "zipCode": "9036325"
  },
  {
    "_id": 5,
    "address": "1044 Venus Lane",
    "zipCode": [
      "99883637232",
      "73488976234"
    ]
  }
]

Außerdem gibt es den Typ „number“, der alle Long-, Integer- oder Double-Werte als Array enthält, das ein Element der angegebenen Typen enthält:

db.addressBook.find( { "zipCode" : { $type : "number" } } )

Ausgabe:

[
{
      "_id": 2,
      address: "25 Moon Place",
      zipCode: 26237
    },
    {
      "_id": 3,
      address: "2324 Neptune Ring",
      zipCode: NumberLong(77622222)
    },
    {
      "_id": 4,
      address: "33 Saturns Moon",
      zipCode: NumberInt(117)
    }
]

Wenn die Dokumente einen Array-Feldtyp haben, gibt der $type Operator die Dokumente zurück, in denen mindestens ein Array-Element dem Typ entspricht, der dem Operator übergeben wurde.

Array-Operatoren

MongoDB verfügt auch über Array-Operatoren, um Dokumente abzufragen, die Arrays enthalten.

Es gibt drei Hauptoperatoren: $all, $elemMatch und $size. Im Folgenden werden wir jeden einzelnen im Detail besprechen.

$all

Der $all Operator wählt die Dokumente aus, in denen der Wert eines Feldes ein Array mit den angegebenen Elementen ist:

{ : { $all: [ <value1> , <value2> ... ] } }

Nehmen wir zum Beispiel an, wir haben eine Sammlung von Dokumenten für ein Bekleidungsgeschäft, die unter Inventar folgendes enthalten.

{
   _id: ObjectId("5234cc89687ea597eabee675"),
   code: "shirt",
   tags: [ "sale", "shirt", "button", "y2k", "casual" ],
   qty: [
          { size: "S", num: 10, color: "blue" },
          { size: "M", num: 45, color: "blue" },
          { size: "L", num: 100, color: "green" }
        ]
},

{
   _id: ObjectId("5234cc8a687ea597eabee676"),
   code: "pant",
   tags: [ "y2k", "trendy", "shine" ],
   qty: [
          { size: "6", num: 100, color: "green" },
          { size: "6", num: 50, color: "blue" },
          { size: "8", num: 100, color: "brown" }
        ]
},

{
   _id: ObjectId("5234ccb7687ea597eabee677"),
   code: "pant2",
   tags: [ "trendy", "shine" ],
   qty: [
          { size: "S", num: 10, color: "blue" },
          { size: "M", num: 100, color: "blue" },
          { size: "L", num: 100, color: "green" }
        ]
},

{
   _id: ObjectId("52350353b2eff1353b349de9"),
   code: "shirt2",
   tags: [ "y2k", "trendy" ],
   qty: [
          { size: "M", num: 100, color: "green" }
        ]
}

Wir möchten alle Dokumente (in diesem Fall die Kleidung) aus dem Inventar abrufen, die mit den Tags „trendy“ und „y2k“ verknüpft sind. Die folgende Abfrage verwendet den Operator $all, wobei der Wert des Feldes tags ein Array ist, dessen Elemente „y2k“ und „trendy“ enthalten:

db.inventory.find( { tags: { $all: [ "y2k", "trendy" ] } } )

Die obige Abfrage gibt Folgendes zurück:

{
   _id: ObjectId("5234cc8a687ea597eabee676"),
   code: "pant",
   tags: [ "y2k", "trendy", "shine" ],
   qty: [
          { size: "6", num: 100, color: "green" },
          { size: "6", num: 50, color: "blue" },
          { size: "8", num: 100, color: "brown" }
        ]
}

{
   _id: ObjectId("52350353b2eff1353b349de9"),
   code: "shirt2",
   tags: [ "y2k", "trendy" ],
   qty: [
          { size: "M", num: 100, color: "green" }
        ]
}

Anhand des obigen Beispiels sehen wir auch, dass der $all Operator einfach die gleiche Funktion wie die $and Operation ausführt.

Alternativ könnten wir auch die folgende Abfrage verwenden, die ein ähnliches Ergebnis wie die obige liefert:

db.inventory.find({
  $and: [
    {
      tags: "y2k"
    },
    {
      tags: "trendy"
    }
  ]
})

$elemMatch

Der $elemMatch Operator findet Dokumente, die ein Array-Feld mit mindestens einem Element enthalten, das allen angegebenen Abfragekriterien entspricht:

{ : { $elemMatch: { <query1>, <query2>, ... } } }

Während wir Vergleichsoperatoren wie $lte und $gte verwenden können, können wir, wenn wir nur eine einzige Abfragebedingung innerhalb von $elemMatch angeben und weder $not noch $ne verwenden, $elemMatch weglassen, da er im Wesentlichen dieselbe Funktion erfüllt.

Bei der Verwendung dieses Operators gibt es noch ein paar weitere Dinge zu beachten, vor allem:

  • Du kannst keinen $where Ausdruck in einer $elemMatch Operation angeben.
  • Du kannst keinen $text Abfrageausdruck in einer $elemMatch Operation angeben.

Wir haben zum Beispiel die folgenden Dokumente in der Sammlung der Schülerergebnisse:

{ _id: 1, results: [ 92, 89, 98 ] }
{ _id: 2, results: [ 85, 99, 99 ] }

Die folgende Abfrage findet nur die Dokumente, bei denen das Ergebnisfeld mindestens ein Element enthält, das größer oder gleich 90 und kleiner als 95 ist:

db.studentresults.find(  { results: { $elemMatch: { $gte: 90, $lt: 95 } } })

Unsere Abfrage gibt das folgende Dokument zurück, da das Element 92 sowohl größer oder gleich 90 als auch kleiner als 95 ist:

{ "_id" : 1, "results" :[ 92, 89, 98 ] }

$size

Der $size Operator gibt die Dokumente zurück, bei denen die Größe des Arrays mit der Anzahl der im Argument angegebenen Elemente übereinstimmt:

{ field: { $size: value } }

Hier ist ein Beispiel:

db.collection.find( { field: { $size: 2 } });

Dies würde alle Dokumente in der angegebenen Sammlung zurückgeben, bei denen das Feld ein Array mit 2 Elementen ist: { field: [ orange, apple] } und { field: [ blue, red] }, aber nicht { field: blue} oder { field: [ raspberry, lemon, grapefruit ] }.

Wir können zwar einen bestimmten Wert als Größe eingeben, aber wir können keine Wertebereiche als Größe angeben.

Geospatiale Operatoren

MongoDB ermöglicht es dir, Geodaten in Form von GeoJSON-Typen zu speichern. GeoJSON ist ein auf der JavaScript-Objektnotation basierendes, offenes Standardformat, das geografische Merkmale darstellen kann und nicht-räumliche Attribute unterstützt. Es gibt zwei Arten von GeoJSON-Operatoren, über die wir in diesem Artikel sprechen werden: Geometriespezifizierer und Abfrageselektoren.

$geometry

Dieser Operator gibt die GeoJSON-Geometrie für die Verwendung mit den folgenden Geodatenabfrageoperatoren an: $geoIntersects $geoWithin ,$nearSphere und $near. $geometry verwendet EPSG:4326 als Standard-Koordinatenreferenzsystem (CRS).

Um GeoJSON-Objekte mit dem Standard-CRS anzugeben, kannst du das folgende Snippet für $geometry verwenden:

$geometry: {
   type: "<GeoJSON object type>",
   coordinates: [ <coordinates> ]
}

Um ein einfaches GeoJSON-Polygon mit einem maßgeschneiderten MongoDB-CRS zu erwähnen, kannst du das folgende Snippet verwenden (du kannst es nur für $geoWithin und $geoIntersects verwenden):

$geometry: {
   type: "Polygon",
   coordinates: [ <coordinates> ],
   crs: {
      type: "name",
      properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" }
   }
}

$polygon

Der $polygon Operator kann verwendet werden, um ein Polygon für eine GeoJSON $geoWithin Abfrage auf Legacy-Koordinatenpaare anzugeben. Diese Abfrage gibt dann Paare zurück, die innerhalb der Grenzen des Polygons liegen. $polygon wird jedoch keine GeoJSON-Objekte abfragen. Um ein Polygon zu definieren, musst du ein Array von Koordinatenpunkten wie folgt angeben:

{
   : {
      $geoWithin: {
         $polygon: [ [ <x1> , <y1> ], [ <x2> , <y2> ], [ <x3> , <y3> ], ... ]
      }
   }
}

Hier ist der letzte Punkt implizit mit dem ersten verbunden. Du kannst so viele Punkte oder Seiten angeben, wie du möchtest.

Die folgende Abfrage gibt zum Beispiel alle Dokumente zurück, deren Koordinaten innerhalb des Polygons liegen, das durch [0,0], [1,5] und [3,3] definiert ist:

db.places.find(
  {
     loc: {
       $geoWithin: { $polygon: [ [ 0 , 0 ], [ 1 , 5 ], [ 3 , 3 ] ] }
     }
  }
)

$geoWithin

Dieser Operator kann verwendet werden, um Dokumente mit Geodaten auszuwählen, die vollständig in einem bestimmten Shape enthalten sind. Die angegebene Form kann entweder ein GeoJSON-Multipolygon, ein GeoJSON-Polygon (entweder mit mehreren Ringen oder mit einem Ring) oder eine Form sein, die durch Legacy-Koordinatenpaare definiert werden kann.

Der $geoWithin Operator nutzt den $geometry Operator, um das GeoJSON Objekt zu erwähnen.

Um GeoJSON-Multipolygone oder Polygone über das Standard-Koordinatenreferenzsystem (CRS) anzugeben, kannst du die folgende Syntax verwenden:

{
   : {
      $geoWithin: {
         $geometry: {
            type: <"Polygon" or "MultiPolygon"> ,
            coordinates: [ <coordinates> ]
         }
      }
   }
}

Bei $geoWithin Abfragen, die GeoJSON-Geometrien mit Flächen größer als eine einzelne Halbkugel erwähnen, würde die Verwendung des Standard-CRS zu Abfragen für die komplementären Geometrien führen.

Um ein einzelnes GeoJSON-Polygon mit einem benutzerdefinierten MongoDB-CRS zu erwähnen, kannst du den unten genannten Prototyp in der $geometry Expression verwenden:

{
   : {
      $geoWithin: {
         $geometry: {
           type: "Polygon" ,
           coordinates: [ <coordinates> ],
           crs: {
              type: "name",
              properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" }
           }
         }
      }
   }
}

Das folgende Beispiel wählt alle Ortsdaten aus, die vollständig innerhalb eines GeoJSON-Polygons liegen, wobei die Fläche des Polygons kleiner als die Fläche einer einzelnen Halbkugel ist:

db.places.find(
   {
     loc: {
       $geoWithin: {
          $geometry: {
             type : "Polygon" ,
             coordinates: [ [ [ 0, 0 ], [ 3, 6 ], [ 6, 1 ], [ 0, 0 ] ] ]
          }
       }
     }
   }
)

$box

Mit $box kannst du ein Rechteck für eine GeoJSON-Abfrage $geoWithin angeben, um Dokumente zu finden, die sich innerhalb der Grenzen des Rechtecks befinden, entsprechend ihrer punktbasierten Standortdaten. Wenn du $geoWithin mit $box verwendest, erhältst du Dokumente, die auf den Koordinaten der Abfrage basieren. In diesem Szenario wird $geoWithin keine GeoJSON Shapes abfragen.

Um den $box Operator zu nutzen, musst du die obere rechte und untere linke Ecke des Rechtecks in einem Array-Objekt angeben:

{ <location field> : { $geoWithin: { $box: [ [ <bottom left coordinates> ],
 [ <upper right coordinates> ] ] } } }

Die oben genannte Abfrage berechnet die Entfernung unter Verwendung der planaren (flachen) Geometrie. Die folgende Abfrage gibt alle Dokumente zurück, die sich innerhalb des Rechtecks mit den Punkten: [0,0], [0,30], [30,0], [30,30]:

db.places.find ( { 
 loc: { $geoWithin: { $box: [ [ 0,0 ], [ 30,30 ] ] } }
} )

$nearSphere

Du kannst $nearSphere verwenden, um einen Punkt zu nennen, für den eine Geodatenabfrage die Dokumente von der nächsten bis zur weitesten Entfernung zurückgibt.

MongoDB verwendet sphärische Geometrie, um die Entfernungen für $nearSphere zu berechnen. Dazu wird ein Geodatenindex wie folgt benötigt:

  1. 2d-Index für Standortdaten, die als alte Koordinatenpaare beschrieben sind. Um einen 2D-Index für GeoJSON-Punkte zu nutzen, musst du den Index für das Koordinatenfeld des GeoJSON-Objekts erstellen.
  2. 2dsphere-Index für Ortsdaten, die als GeoJSON-Punkte beschrieben sind.

Um einen GeoJSON-Punkt zu erwähnen, kannst du die folgende Syntax verwenden:

{
  $nearSphere: {
     $geometry: {
        type : "Point",
        coordinates : [ <longitude>, <latitude> ]
     },
     $minDistance: <distance in meters>,
     $maxDistance: <distance in meters> 
  }
}

Hier sind $minDistance und $maxDistance optional. $minDistance kann die Ergebnisse auf die Dokumente beschränken, die mindestens die angegebene Entfernung vom Zentrum haben. Du kannst $maxDistance für beide Indizes verwenden.

Betrachte nun eine Sammlung von „Orten“, die aus Dokumenten mit einem Ortsfeld besteht, das einen 2dsphere-Index hat. Das folgende Beispiel würde die Punkte zurückgeben, die mindestens 2.000 Meter und höchstens 6.000 Meter von dem von dir gewählten Punkt entfernt sind, und zwar in der Reihenfolge vom nächsten zum weitesten Punkt:

db.places.find(
   {
     location: {
        $nearSphere: {
           $geometry: {
              type : "Point",
              coordinates : [ -43.9532, 50.32 ]
           },
           $minDistance: 2000,
           $maxDistance: 6000
        }
     }
   }
)

$geoIntersects

Mit dem $geoIntersects Operator kannst du Dokumente auswählen, deren Geodaten sich mit einem bestimmten GeoJSON-Objekt überschneiden (d.h. bei denen die Konvergenz des angegebenen Objekts und der Daten nicht leer ist). Er nutzt den $geometry Operator, um das GeoJSON-Objekt anzugeben.

Um GeoJSON-Multipolygone oder Polygone durch das Standard-Koordinatenreferenzsystem (CRS) zu erwähnen, kannst du die folgende Syntax verwenden:

{ <location field>: {
     $geoIntersects: {
        $geometry: {
           type: "<GeoJSON object type>" ,
           coordinates: [ <coordinates> ]
        }
     }
  }
}

Die folgende Instanz verwendet $geoIntersects, um alle Ortsdaten auszuwählen, die sich mit dem durch das Koordinatenarray beschriebenen Polygon schneiden:

db.places.find(
   {
     loc: {
       $geoIntersects: {
          $geometry: {
             type: "Polygon" ,
             coordinates: [
               [ [ 0, 0 ], [ 2, 6 ], [ 4, 1 ], [ 0, 0 ] ]
             ]
          }
       }
     }
   }
)

$center

Der $center Operator nennt einen Kreis für eine $geoWithin Abfrage, die die alten Koordinatenpaare zurückgibt, die innerhalb der Grenzen des Kreises liegen.

$center gibt keine GeoJSON-Objekte zurück. Um den $center Operator zu nutzen, musst du ein Array angeben, das folgendes enthält:

  1. Den Radius des Kreises, gemessen in den Einheiten, die das Koordinatensystem verwendet.
  2. Die Gitterkoordinaten des Mittelpunkts des Kreises.
{
  <location field> : {
      $geoWithin: { $center: [ [ <x> , <y> ] , <radius> ] }
   }
}

Das folgende Beispiel gibt alle Dokumente zurück, deren Koordinaten sich innerhalb des Kreises mit dem Mittelpunkt [2,3] und dem Radius 40 befinden:

db.places.find(
   { loc: { $geoWithin: { $center: [ [2, 3], 40 ] } } }
)

Projektionsoperatoren

Du kannst Projektionsoperatoren verwenden, um die Felder zu nennen, die von einer Operation zurückgegeben werden. MongoDB Projektionsoperatoren ermöglichen es, die Funktion find() mit Argumenten zur Datenfilterung zu verwenden. Dies hilft den Nutzern, nur die benötigten Datenfelder aus einem Dokument zu extrahieren. So kannst du transparente und übersichtliche Daten projizieren, ohne die Gesamtleistung der Datenbank zu beeinträchtigen.

$elemMatch (Projektion)

Der $elemMatch Operator ist dafür verantwortlich, den Inhalt eines Feldes aus den Abfrageergebnissen so einzuschränken, dass es nur das erste Element enthält, das der $elemMatch Bedingung entspricht.

Hier sind ein paar Dinge, die du beachten musst, bevor du $elemMatch verwendest:

  • Ab MongoDB 4.4 gibt die $elemMatch Projektion eines bestehenden Feldes unabhängig von der Reihenfolge der Felder im Dokument das Feld nach der Einbeziehung anderer bestehender Felder zurück.
  • Sowohl der $elemMatch als auch der $ Operator projizieren das erste übereinstimmende Element aus einem Array, das auf einer bestimmten Bedingung basiert. Der $ Operator würde das erste übereinstimmende Array-Element aus jedem Dokument in einer Sammlung auf der Grundlage einer Bedingung aus der Abfrageanweisung projizieren, während der $elemMatch Projektionsoperator ein explizites Bedingungsargument benötigt. So kannst du auf der Grundlage einer Bedingung projizieren, die nicht in der Abfrage enthalten ist, oder wenn du auf der Grundlage verschiedener Felder in den eingebetteten Dokumenten des Arrays projizieren musst.

Du solltest außerdem die folgenden Einschränkungen beachten, bevor du den $elemMatch Operator auf deine Daten anwendest:

  • Du kannst einen $text Abfrageausdruck nicht innerhalb eines $elemMatch Operators erwähnen.
  • db.collection.find() operationen auf Ansichten unterstützen den $elemMatch Projektionsoperator nicht.

Das folgende Beispiel für den $elemMatch Projektionsoperator geht von einer Sammlung schools mit den folgenden Dokumenten aus:

{
 _id: 1,
 zipcode: "63108",
 students: [
              { name: "mark", school: 102, age: 9 },
              { name: "geoff", school: 101, age: 13 },
              { name: "frank", school: 104, age: 12 }
           ]
}
{
 _id: 2,
 zipcode: "63110",
 students: [
              { name: "harry", school: 103, age: 14 },
              { name: "george", school: 103, age: 7 },
           ]
}
{
 _id: 3,
 zipcode: "63108",
 students: [
              { name: "harry", school: 103, age: 14 },
              { name: "george", school: 103, age: 7 },
           ]
}
{
 _id: 4,
 zipcode: "63110",
 students: [
              { name: "jim", school: 103, age: 9 },
              { name: "michael", school: 103, age: 12 },
           ]
}

In diesem Fall sucht die Operation find() nach allen Dokumenten, bei denen der Wert des Feldes Postleitzahl 63110 ist. Die $elemMatch Projektion würde nur das erste übereinstimmende Element des students Arrays zurückgeben, in dem das Feld school den Wert 103 hat:

db.schools.find( { zipcode: "63110" },
                 { students: { $elemMatch: { school: 103 } } } )

So würde das Ergebnis aussehen:

{ "_id" : 2, "students" : [ { "name" : "harry", "school" : 103, "age" : 14 } ] }
{ "_id" : 4, "students" : [ { "name" : "jim", "school" : 103, "age" : 9 } ] }

$slice (Projektion)

Der $slice Projektionsoperator kann verwendet werden, um die Anzahl der Elemente in einem Array anzugeben, die im Abfrageergebnis zurückgegeben werden sollen:

db.collection.find(
   <query> ,
   { <arrayField> : { $slice: <number> } }
);

Er kann auch folgendermaßen ausgedrückt werden:

db.collection.find(
  <query> ,
   { <arrayField> : { $slice: [ <number> , <number> ] } }
);

Um das zu demonstrieren, kannst du eine Beispielsammlung von Tweets mit den folgenden Dokumenten erstellen:

db.posts.insertMany([
   {
     _id: 1,
     title: "Nuts are not blueberries.",
     comments: [ { comment: "0. true" }, { comment: "1. blueberries aren't nuts."} ]
   },
   {
     _id: 2,
     title: "Coffee please.",
     comments: [ { comment: "0. Indubitably" }, { comment: "1. Cuppa tea please" }, { comment: "2. frappucino" }, { comment: "3. Mocha latte" }, { comment: "4. whatever" } ]
   }
])

Die folgende Operation würde den $slice Projektionsoperator auf das Array tweets anwenden, um das Array mit seinen ersten beiden Elementen zurückzugeben. Wenn ein Array weniger als zwei Elemente enthält, werden alle Elemente des Arrays zurückgegeben:

db.posts.find( {}, { comments: { $slice: 2 } } )

Diese Operation würde die folgenden Dokumente zurückgeben:

{
   "_id" : 1,
   "title" : "Nuts are not blueberries.",
   "comments" : [ { "comment" : "0. true" }, { "comment" : "1. blueberries aren't nuts." } ]
}
{
   "_id" : 2,
   "title" : "Coffee please.",
   "comments" : [ { "comment" : "0. Indubitably" }, { "comment" : "1. Cuppa tea please" } ]
}

$ (Projektion)

Der Positionsoperator $ schränkt den Inhalt eines Arrays ein und gibt das erste Element zurück, das der Abfragebedingung des Arrays entspricht. Du kannst $ im Projektionsdokument der Methode find() oder der Methode findOne() verwenden, wenn du nur ein bestimmtes Array-Element in ausgewählten Dokumenten benötigst.

So sieht die Syntax für den $ Operator aus:

db.collection.find( { <array>: <condition> ... },
                    { "<array>.$": 1 } )
db.collection.find( { <array.field>: <condition> ...},
                    { "<array>.$": 1 } )

In diesem Beispiel besteht die Sammlung students aus den folgenden Dokumenten:

{ "_id" : 1, "semester" : 2, "grades" : [ 75, 67, 93 ] }
{ "_id" : 2, "semester" : 2, "grades" : [ 60, 68, 72 ] }
{ "_id" : 3, "semester" : 2, "grades" : [ 95, 82, 67 ] }
{ "_id" : 4, "semester" : 3, "grades" : [ 89, 95, 70 ] }
{ "_id" : 5, "semester" : 3, "grades" : [ 68, 98, 82 ] }
{ "_id" : 6, "semester" : 3, "grades" : [ 65, 70, 76 ] }

In der folgenden Abfrage gibt die Projektion { "grades.$": 1 } nur das erste Element zurück, das größer oder gleich 89 für das Feld grades ist:

db.students.find( { semester: 2, grades: { $gte: 89 } },
                  { "grades.$": 1 } )

Dieser Vorgang gibt die folgenden Dokumente zurück:

{"_id": 1, "grades": [93] }

Auswertungsoperatoren

Du kannst die MongoDB-Auswertungsoperatoren nutzen, um die gesamte Datenstruktur oder einzelne Felder in einem Dokument zu beurteilen.

Schauen wir uns einige gängige MongoDB-Auswertungsoperatoren an.

$mod

Mit diesem Operator kannst du Dokumente abgleichen, bei denen der Wert eines bestimmten Feldes gleich dem Rest ist, nachdem er durch einen bestimmten Wert geteilt wurde:

{ field: { $mod: [ divisor, remainder ] } }

Angenommen, du hast eine Tabelle mit Autos verschiedener Marken, die du in deinem Ausstellungsraum besitzt. Die folgende Abfrage würde dir alle Automarken liefern, deren Bestandsnummern ein Vielfaches von 250 sind.

db.cars.find ( { qty: { $mod: [ 250,0 ] } } )

$jsonSchema

Mit $jsonSchema kannst du die Dokumente abgleichen, die mit dem angegebenen JSON-Schema übereinstimmen. Die MongoDB-Implementierung des JSON-Schemas enthält zusätzlich das Schlüsselwort bsonType, mit dem du alle BSON-Typen innerhalb des $jsonSchema -Operators verwenden kannst.

bsonType kann die gleichen String-Aliase akzeptieren, die du auch für den type Operator verwendest. So würde die Syntax von $jsonSchema aussehen:

{ $jsonSchema: <JSON Schema object> }

Hier wird das JSON-Schema-Objekt auf der Grundlage des Draft 4 des JSON-Schema-Standards formatiert:

{ <keyword1>: <value1>, ... }

Hier ist ein Beispiel, das zeigt, wie $jsonSchema funktioniert:

{ $jsonSchema: {
     required: [ "name", "major", "gpa", "address" ],
     properties: {
        name: {
           bsonType: "string",
           description: "must be a string and is required"
        },
        address: {
           bsonType: "object",
           required: [ "zipcode" ],
           properties: {
               "street": { bsonType: "string" },
               "zipcode": { bsonType: "string" }
           }
        }
     }
  }
}

Du kannst $jsonSchema auch in einem Dokumentenvalidator verwenden, um das angegebene Schema bei Aktualisierungs- und Einfügevorgängen durchzusetzen:

db.createCollection(<collection> , { validator: { $jsonSchema: <schema> } } )
db.runCommand( { collMod: <collection>, validator:{ $jsonSchema: <schema> } } )

Beachte, dass es einige Dinge gibt, die der $jsonSchema Operator nicht unterstützt:

  1. Der Integer-Typ. Du musst den BSON-Typ long oder int mit dem Schlüsselwort bsonType nutzen.
  2. Unbekannte Schlüsselwörter.
  3. Verknüpfungseigenschaften und die Hypermedia des JSON-Schemas sowie die Verwendung von JSON-Referenzen und JSON-Zeigern.

$Text

Der $text Operator sucht nach einem Text innerhalb des Inhalts des angegebenen Feldes, der mit einem Textindex indiziert ist:

{  
  $text:  
    {  
      $search: <string>,  
      $language: <string>,  
      $caseSensitive: <boolean>,  
      $diacriticSensitive: <boolean>   
    }  
}

In diesem Fall durchforstet der folgende Codeschnipsel die Tabelle, um alle Autos herauszufiltern, die den Text „Porsche“ enthalten:

db.cars.find( { $text: { $search: "Porsche" } } )

$regex

Der Operator $regex bietet reguläre Ausdrücke, um Zeichenfolgen in Abfragen nach Mustern abzugleichen. MongoDB nutzt reguläre Ausdrücke, die mit Perl kompatibel sind:

{<field> : /pattern/ <options>}

Das folgende Beispiel würde helfen, alle Autos herauszufiltern, die die Zeichenfolge „$78900“ enthalten:

db.cars.find( { price: { $regex: /$78900/ } } )

$expr

Der $expr Operator ermöglicht es dir, Aggregationsausdrücke in der Abfragesprache zu nutzen:

{ $expr: { <expression> } }

Du kannst auch $expr verwenden, um Abfrageausdrücke zu erstellen, die Felder aus demselben Dokument in einer $match Stufe vergleichen. Wenn die $match Stufe Teil einer $lookup Stufe ist, kann $expr Felder mit Hilfe von let-Variablen vergleichen.

$where

Du kannst den $where Operator nutzen, um entweder einen String mit einer vollständigen JavaScript-Funktion oder einen JavaScript-Ausdruck an das Abfragesystem zu übergeben. Der $where Operator bietet mehr Flexibilität, aber die Datenbank muss die JavaScript-Funktion oder den Ausdruck für jedes Dokument in der Sammlung verarbeiten. Du kannst dieses Dokument in der JavaScript-Funktion oder dem Ausdruck referenzieren, indem du entweder obj oder this verwendest.

Hier ist ein Beispiel für die Syntax:

{ $where: <string|JavaScript Code> }

Bevor wir uns mit einem Beispiel für den $where Operator beschäftigen, gibt es einige wichtige Punkte zu beachten:

  • Du solltest den $where Abfrageoperator nur für Dokumente der obersten Ebene verwenden. Der $where Abfrageoperator funktioniert nicht in einem verschachtelten Dokument, wie bei einer $elemMatch Abfrage.
  • Im Allgemeinen solltest du $where nur verwenden, wenn du deine Abfrage nicht mit einem anderen Operator ausdrücken kannst. Wenn du $where verwenden musst, stelle sicher, dass du mindestens einen anderen Standard-Abfrageoperator verwendest, um die Ergebnismenge zu filtern. Die unabhängige Verwendung von $where erfordert für eine ordnungsgemäße Ausführung eine Sammelabfrage.

Hier ist ein Beispiel, um das zu verdeutlichen:

db.cars.find( { $where: function() {  
   return (hex_md5(this.name)== "9a43e617b50cd379dca1bc6e2a8")  
} } );

Bitweise Operatoren

Bitwise-Operatoren geben Daten auf der Grundlage von Bit-Positionsbedingungen zurück. Einfach ausgedrückt: Sie werden verwendet, um numerische oder binäre Werte abzugleichen, bei denen jedes Bit aus einer Reihe von Bitpositionen den Wert 1 oder 0 hat.

$bitsAllSet

Dieser Operator findet alle Dokumente, bei denen alle in der Abfrage angegebenen Bitpositionen im Feld gesetzt (d.h. 1) sind:

{ <field> : { $bitsAllSet: <numeric bitmask> } }
{ <field> : { $bitsAllSet: < BinData bitmask> } }
{ <field> : { $bitsAllSet: [ <position1> , <position2> , ... ] } }

Der Feldwert sollte entweder eine BinData-Instanz oder numerisch sein, damit $bitsAllSet mit dem aktuellen Dokument übereinstimmt.

Im folgenden Beispiel nutzen wir eine Sammlung mit den folgenden Dokumenten:

db.collection.save({ _id: 1, a: 54, binaryValueofA: "00110110" })
db.collection.save({ _id: 2, a: 20, binaryValueofA: "00010100" })
db.collection.save({ _id: 3, a: 20.0, binaryValueofA: "00010100" })
db.collection.save({ _id: 4, a: BinData(0, "Zg=="), binaryValueofA: "01100110" })

Die unten stehende Abfrage verwendet den Operator $bitsAllSet, um zu prüfen, ob das Feld a Bits an Position 1 und Position 5 hat, wobei das niedrigstwertige Bit an Position 0 wäre:

db.collection.find( { a: { $bitsAllSet: [ 1, 5 ] } })

Diese Abfrage würde mit den folgenden Dokumenten übereinstimmen:

{ "_id" : 1, "a" : 54, "binaryValueofA" : "00110110" }
{ "_id" : 4, "a" : BinData(0,"Zg=="), "binaryValueofA" : "01100110" }

$bitsAllClear

Der Operator $bitsAllClear findet Dokumente, in denen alle von der Abfrage angegebenen Bitpositionen leer sind oder 0:

{ <field> : { $bitsAllClear: <numeric bitmask> } }
{ <field> : { $bitsAllClear: < BinData bitmask> } }
{ <field> : { $bitsAllClear: [ <position1> , <position2> , ... ] } }

Wir verwenden hier das Beispiel für $bitsAllSet, um die Verwendung von $bitsAllClear zu demonstrieren. Die folgende Abfrage würde diesen Operator verwenden, um zu prüfen, ob in Feld a die Bits an den Positionen 1 und 5 gelöscht sind:

db.collection.find( { a: { $bitsAllClear: [ 1, 5 ] } } )

Diese Abfrage würde mit den folgenden Dokumenten übereinstimmen:

{ "_id" : 2, "a" : 20, "binaryValueofA" : "00010100" }
{ "_id" : 3, "a" : 20, "binaryValueofA" : "00010100" }

Meta-Operatoren

Es gibt verschiedene Abfragemodifikatoren, mit denen du das Verhalten oder die Ausgabe einer Abfrage in MongoDB ändern kannst. Die Treiberschnittstellen stellen möglicherweise Cursor-Methoden zur Verfügung, die sie für deine Verwendung verpacken.

$hint

MongoDB hat $hint seit v3.2 veraltet. Für MongoDB-Treiber wie Go, Java, Scala, Ruby, Swift usw. kann dieser Operator jedoch weiterhin verfügbar sein. Er kann den Abfrageoptimierer dazu zwingen, einen bestimmten Index zu nutzen, um die Abfrage zu erfüllen, der dann entweder nach Dokument oder nach Indexname angegeben werden kann.

Du kannst den $hint Operator auch verwenden, um Indexierungsstrategien und die Abfrageleistung zu testen. Nimm zum Beispiel die folgende Operation:

db.users.find().hint( { age: 1 } )

Diese Operation würde alle Dokumente in der Sammlung mit dem Namen users zurückgeben, indem sie den Index für das Feld age nutzt.

Du kannst auch einen Hinweis angeben, indem du eine der folgenden Formen verwendest:

db.users.find()._addSpecial( "$hint", { age : 1 } )
db.users.find( { $query: {}, $hint: { age : 1 } } )

Wenn ein Indexfilter für die Abfrageform existiert, würde MongoDB den $hint einfach ignorieren.

$comment

Mit dem Operator $comment kannst du einen Kommentar an eine Abfrage anhängen, egal in welchem Kontext $query erscheint. Da Kommentare in das Profilprotokoll übertragen werden, kann das Hinzufügen eines Kommentars die Interpretation und Verfolgung deines Profils erleichtern.

Du kannst $comment auf eine von drei Arten nutzen:

db.collection.find( { <query> } )._addSpecial( "$comment", <comment> )
db.collection.find( { <query> } ).comment( <comment> )
db.collection.find( { $query: { <query> }, $comment: <comment> } )

Wenn du Kommentare an Abfrageausdrücke in anderen Kontexten anhängen willst, wie z. B. mit db.collection.update(), verwende den Abfrageoperator $comment anstelle des Metaoperators.

$max

Du kannst einen $max Wert erwähnen, um die exklusive Obergrenze für einen bestimmten Index anzugeben, um die Ergebnisse von find() einzuschränken. Dieser Operator gibt die Obergrenze für alle Schlüssel einer bestimmten Reihenfolge im Index an.

Mongosh bietet dir die folgende max() Wrapper-Methode:

db.collection.find( { <query> } ).max( { field1: <max value> , ... fieldN: <max valueN> } )

Du kannst $max auch mit den folgenden beiden Formen angeben:

db.collection.find( { <query> } )._addSpecial( "$max", { field1: <max value1> ,
 ... fieldN: <max valueN> } )
db.collection.find( { $query: { <query> }, $max: { field1: <max value1> ,
 ... fieldN: <max valueN> } } )

Wenn du z.B. die exklusive Obergrenze angeben willst, beachte die folgenden Operationen auf einer Sammlung namens collection, die einen Index { age: 1 } enthält:

db.collection.find( { <query> } ).max( { age: 100 } ).hint( { age: 1 } )

Diese Operation beschränkt die Abfrage auf die Dokumente, in denen das Feld Alter kleiner als 100 ist, und erzwingt einen Abfrageplan, der den Index { age: 1 } von minKey bis 100 durchsucht.

$explain

Dieser Operator gibt dir Informationen über den Abfrageplan. Er gibt ein Dokument zurück, das die Indizes und Prozesse beschreibt, die für die Rückgabe der Abfrage verwendet werden. Das kann nützlich sein, wenn du versuchst, eine Abfrage zu optimieren.

Du kannst den $explain Operator in einer der folgenden Formen angeben:

db.collection.find()._addSpecial( "$explain", 1 )
db.collection.find( { $query: {}, $explain: 1 } )

Best Practices für MongoDB-Operatoren

In diesem Abschnitt werfen wir einen Blick auf einige der besten Praktiken bei der Verwendung dieser MongoDB-Operatoren.

Einbetten und referenzieren

Die Einbettung ist eine natürliche Erweiterung der Datenmodellierung. Sie ermöglicht es dir, Anwendungs-Joins zu vermeiden, was Aktualisierungen und Abfragen reduzieren kann.

Du kannst Daten mit einer 1:1-Beziehung in ein einzelnes Dokument einbetten. Aber auch Daten mit einer Many:1-Beziehung, bei der „viele“ Objekte in ihren übergeordneten Dokumenten erscheinen, können valide Kandidaten sein.

Diese Art von Daten im selben Dokument zu speichern, klingt nach einer umsichtigen Entscheidung. Die Einbettung bietet jedoch eine bessere Leistung für Lesevorgänge mit dieser Art von Datenlokalität.

Eingebettete Datenmodelle können Entwicklern auch helfen, verknüpfte Daten in einem einzigen Schreibvorgang zu aktualisieren. Das funktioniert, weil Schreibvorgänge für einzelne Dokumente transaktional sind.

Du solltest die Referenzierung für die folgenden Szenarien in Betracht ziehen:

  • Wenn du ein Dokumentsegment aktualisierst und es immer länger wird, während der Rest des Dokuments statisch ist.
  • Wenn auf ein Dokument zugegriffen wird, das aber Daten enthält, die selten verwendet werden. Das Einbetten würde nur den Speicherbedarf erhöhen, daher ist die Referenzierung sinnvoller.
  • Wenn die Größe des Dokuments die 16 MB-Grenze von MongoDB überschreitet. Das kann passieren, wenn du viele 1:1-Beziehungen modellierst (z. B. Mitarbeiter:Abteilung).

Untersuche Profiling und Abfragemuster

Für die meisten Entwickler/innen besteht der erste Schritt zur Leistungsoptimierung darin, die tatsächlichen und erwarteten Abfragemuster zu verstehen. Sobald du die Abfragemuster deiner Anwendung gut genug kennst, kannst du dein Datenmodell erstellen und geeignete Indizes auswählen.

MongoDB-Entwickler haben Zugang zu verschiedenen leistungsstarken Tools, mit denen sie die Leistung verbessern können. Das bedeutet aber nicht, dass Abfrageprofile und -muster ignoriert werden können.

Eine einfache Möglichkeit, die Leistung zu steigern, ist zum Beispiel, deine Abfragemuster zu analysieren und zu verstehen, wo du Daten einbetten kannst. Weitere Möglichkeiten, die Leistung von MongoDB zu verbessern, nachdem du deine wichtigsten Abfragemuster identifiziert hast, sind:

  • Sicherstellen, dass du Indizes für alle Felder hast, die du abfragst.
  • Die Ergebnisse häufiger Unterabfragen auf Dokumenten speichern, um die Leselast zu verringern.
  • Einen Blick in deine Logs werfen, um langsame Abfragen zu finden und dann deine Indizes überprüfen.

Datenindizierung und -modellierung überprüfen

Während du dein Datenmodell erstellst, musst du entscheiden, wie du die Beziehungen zwischen den Daten modellieren willst. Ein Beispiel für eine anwendungsspezifische Überlegung ist die Entscheidung, ob ein Dokument eingebettet werden soll oder ob stattdessen ein Verweis auf verschiedene Dokumente in unterschiedlichen Sammlungen erstellt werden soll.

Ein großer Vorteil von JSON-Dokumenten ist, dass sie es Entwicklern ermöglichen, Daten entsprechend den Anforderungen der Anwendung zu modellieren. Durch die Verschachtelung von Unterdokumenten und Arrays kannst du komplexe Beziehungen zwischen Daten modellieren, indem du einfache Textdokumente nutzt.

Du kannst MongoDB auch für die Modellierung folgender Dinge verwenden:

  • Geodaten
  • Tabellarische, flache und spaltenförmige Strukturen
  • Einfache Schlüssel-Werte-Paare
  • Zeitreihendaten
  • Kanten und Knoten von zusammenhängenden Graphenstrukturen und Ähnlichem

Sharding und Replikation überwachen

Die Replikation kann entscheidend zur Leistungssteigerung beitragen, da sie die Datenverfügbarkeit durch horizontale Skalierung erhöht. Replikation kann zu einer besseren Leistung und mehr Sicherheit durch Redundanz führen.

Die Leistungsüberwachung kann mühsam sein und zusätzliche Ressourcen und Zeit erfordern, um einen reibungslosen Betrieb zu gewährleisten. Du kannst die auf dem Markt erhältlichen Tools zur Leistungsüberwachung nutzen, die auf deine speziellen Bedürfnisse zugeschnitten sind.

Kinsta APM kann zum Beispiel mit Zeitstempeln versehene Informationen über die MySQL-Datenbankabfragen, PHP-Prozesse, externe HTTP-Aufrufe und vieles mehr erfassen. Du kannst dieses kostenlose Tool auch zur Fehlersuche nutzen:

  • Lange API-Aufrufe
  • Lange externe URL-Anfragen
  • Langsame Datenbankabfragen, um nur einige zu nennen.

In MongoDB kann die Replikation durch Replikatsätze erreicht werden, mit denen Entwickler Daten von einem primären Knoten oder Server auf mehrere sekundäre Server kopieren können. So kann die Replikation einige Abfragen auf den Secondaries und nicht auf dem Primary Server ausführen, was Konflikte vermeidet und zu einer besseren Lastverteilung führt.

Sharded-Cluster in MongoDB sind eine weitere Möglichkeit, die Leistung zu verbessern. Ähnlich wie die Replikation kann das Sharding genutzt werden, um große Datensätze auf mehrere Server zu verteilen.

Mithilfe eines Shard-Schlüssels können Entwickler/innen Shards oder Teile von Daten auf mehrere Server kopieren. Diese Server können zusammenarbeiten, um alle Daten zu nutzen.

Sharding hat eine Reihe von Vorteilen, darunter die horizontale Skalierung für Schreib- und Lesevorgänge, eine höhere Verfügbarkeit und eine größere Speicherkapazität.

Speichernutzung bestimmen

MongoDB ist am leistungsfähigsten, wenn das Working Set einer Anwendung (d. h. häufig aufgerufene Daten und Indizes) ohne Probleme in den Arbeitsspeicher passt. Auch wenn andere Faktoren für die Leistung ausschlaggebend sind, ist die Größe des Arbeitsspeichers für die Dimensionierung der Instanz am wichtigsten.

Wenn das Arbeitsset einer Anwendung in den Arbeitsspeicher passt, muss die Leseaktivität auf der Festplatte gering sein. Wenn dein Arbeitsset jedoch den Arbeitsspeicher des Instance-Servers oder die Größe überschreitet, steigt die Leseaktivität rapide an.

Wenn du das bemerkst, kannst du das Problem vielleicht lösen, indem du auf eine größere Instanz mit mehr Arbeitsspeicher umsteigst.

Platziere mehrwertige Felder am Ende

Wenn du eine Reihe von Feldern indizierst und eines der Felder, die du abfragen willst, einen dieser „mehrwertigen“ Operatoren verwendet, solltest du ihn an das Ende des Indexes stellen. Du musst den Index so anordnen, dass die abgefragten Felder für exakte Werte an erster Stelle stehen und die „mehrwertigen“ Operatoren zuletzt im Index auftauchen.

Eine Ausnahme hiervon wäre die Sortierung nach den Feldern. Platziere diese zwischen den „mehrwertigen“ und den exakten Feldern, um den Aufwand für das Sortieren im Speicher zu verringern.

Zusammenfassung

Bei MongoDB ist Geschwindigkeit das A und O. Um Abfragen schnell zu beantworten, nutzt MongoDB Operatoren, um mathematische oder logische Aufgaben auszuführen. Kurz gesagt: MongoDB-Operatoren zu verstehen, ist der Schlüssel zur Beherrschung von MongoDB.

In diesem Artikel werden einige der wichtigsten MongoDB-Operatoren vorgestellt, die du für deine Daten verwenden kannst, z. B. Vergleichsoperatoren, logische Operatoren, Meta-Operatoren und Projektionsoperatoren, um nur einige zu nennen. Außerdem erfährst du, wie du die MongoDB-Operatoren nutzen kannst und welche Best Practices es gibt, damit du das Beste aus ihnen herausholen kannst.

Welche(n) der Operatoren verwendest du am häufigsten und warum? Teile uns deine Meinung in den Kommentaren mit – wir würden uns freuen, sie zu hören!

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.