In elk bedrijf zijn gegevens je grootste troef. Door gegevens te analyseren kun je beslissingen nemen over klantentrends en kan je gedrag voorspellen. Dit verhoogt de winstgevendheid van het bedrijf en de effectieve besluitvorming.

Zonder databasesoftware zou een eenvoudige taak als het vinden van het gemiddelde van alle waarden in een systeem vol records al snel vervelend worden. Gelukkig hebben databases het analyseren van gegevens gemakkelijker en sneller gemaakt met functies en operators.

Dit artikel zal een en ander uitleggen over de operators die in de MongoDB databasesoftware worden gebruikt.

Wat zijn MongoDB operators?

MongoDB is een NoSQL databasesoftware die documentgeoriënteerde informatie beheert.

Een van de belangrijkste kenmerken van MongoDB is zijn snelheid. Om queries sneller terug te geven kan MongoDB operators gebruiken om specifieke functies uit te voeren.

Operators zijn speciale symbolen die compilers helpen bij het uitvoeren van wiskundige of logische taken. MongoDB biedt verschillende soorten operators voor interactie met de database.

MongoDB operatortypes

Er zijn negen soorten operators, elk genoemd naar zijn functie. Zo gebruiken logische operators logische bewerkingen. Om ze uit te voeren moet je een specifiek sleutelwoord gebruiken en de syntaxis volgen. Ze zijn echter vrij gemakkelijk te volgen!

Aan het eind van dit artikel zul je de basis van elke operator en zijn functies kennen.

Logische operators

Logische operators worden vaak gebruikt om gegevens te filteren op basis van de gegeven voorwaarden. Ze maken ook de evaluatie van vele voorwaarden mogelijk, die we nader zullen bespreken.

Hieronder staan enkele logische operators die je kunt gebruiken:

$and

Een “and” condition voert een logische “en” bewerking uit op een matrix van twee of meer expressions. Het selecteert de documenten waar aan alle voorwaarden van de expressions is voldaan.

Dit is de standaard syntaxis voor de expression $and:

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

Als we bijvoorbeeld documenten willen selecteren waarvan de prijs $10 is en de hoeveelheid minder dan 15, kunnen we de volgende query invoeren:

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

$or

Een “or” condition voert een logische “of” bewerking uit op een matrix van twee of meer expressions. Het selecteert de documenten waar minstens één van de expressions waar is.

Dit is de standaard syntaxis voor de expression $or:

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

Als we bijvoorbeeld documenten willen selecteren waar de prijs $10 of de hoeveelheid minder dan 15 is, kunnen we de volgende query invoeren:

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

We hoeven de expression niet te beperken tot twee criteria – we kunnen er meer toevoegen. De onderstaande query selecteert bijvoorbeeld die documenten waarvan de prijs gelijk is aan $10, de hoeveelheid kleiner is dan 15, of de tag stationair is:

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

Bij het uitvoeren van deze clausules voert MongoDB ofwel een verzamelscan of een indexscan uit. Als alle indexen de clausules ondersteunen, dan gebruikt MongoDB indexen om een $or expression te controleren. Anders gebruikt het in plaats daarvan een verzamelscan.

Maar als je de criteria in hetzelfde veld wilt testen, kun je beter de $in operator gebruiken dan de $or operator. Als je bijvoorbeeld een verzameling documenten wilt waar de hoeveelheid ofwel 10 ofwel 20 is, moet je misschien in plaats daarvan de onderstaande $in query uitvoeren:

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

We behandelen later meer over de $in operator.

$nor

Deze operator voert een logische “nor” bewerking uit op een array met behulp van een of meer expressions. Vervolgens selecteert hij de documenten die niet voldoen aan de query-expressions. Eenvoudiger gezegd: hij doet het tegenovergestelde van de voorwaarde $or.

Dit is de algemene syntaxis:

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

Laten we de volgende query als voorbeeld nemen:

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

Deze query selecteert de documenten die bevatten:

  • een price veldwaarde die niet gelijk is aan $3,99, en een sale waarde die niet gelijk is aan true; of
  • een price veldwaarde niet gelijk aan $3,99, en een leeg of afwezig sale veld; of
  • geen price veld, en een sale veld niet gelijk aan waar; of
  • noch price veld, noch sale veld ingevuld of aanwezig.

$not

Deze operator voert een logische “niet” operatie uit op een array voor de gespecificeerde expression. Het selecteert vervolgens de documenten die niet overeenkomen met de query expressions. Hieronder vallen documenten die het veld niet bevatten.

Dit is de algemene syntaxis:

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

Neem bijvoorbeeld de volgende query:

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

Deze query zou die documenten selecteren die bevatten:

  • een price veld waarvan de waarde groter is dan of gelijk aan $3,99; en
  • een prijsveld niet ingevuld of niet bestaand.

Vergelijkingsoperators

Vergelijkingsoperators kunnen worden gebruikt om waarden in één of meer documenten te vergelijken.

Hieronder staat een voorbeeldcode van een eenvoudige inventarisverzameling voor een supermarktwinkel:

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

We zullen dit voorbeeld gebruiken terwijl we elke vergelijkingsoperator in detail bespreken.

Gelijk aan ($eq)

Deze operator komt overeen met waarden die gelijk zijn aan de gegeven waarde:

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

Als we bijvoorbeeld een specifiek document uit de inventarisverzameling willen ophalen met de exacte hoeveelheidswaarde “20”, zouden we het volgende commando invoeren:

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

De query zou het volgende opleveren:

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

Groter dan ($gt)

Deze operator komt overeen als de waarden groter zijn dan de gegeven waarde:

{ field: { $gt: value } }

In dit voorbeeld halen we de documenten op waarbij de hoeveelheid groter is dan 15:

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

De query zou het volgende opleveren:

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

Minder dan ($lt)

Deze operator komt overeen als waarden kleiner zijn dan de opgegeven waarde:

{ field: { $lt: value } }

Laten we de documenten vinden met een hoeveelheid van minder dan 25:

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

De query zou het volgende opleveren:

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

Groter of gelijk aan ($gte)

Deze operator komt overeen als de waarden groter of gelijk zijn aan de gegeven waarde:

{ field: { $gte: value } }

In dit voorbeeld halen we de documenten op waarbij de hoeveelheid groter of gelijk is aan 25:

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

Deze query zou het volgende opleveren:

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

Minder of gelijk aan ($lte)

Deze operator komt alleen overeen als de waarden minder of gelijk zijn aan de gegeven waarde:

{ field: { $lte: value } }

Laten we de documenten vinden met een hoeveelheid kleiner dan of gelijk aan 25.

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

We kunnen verwachten dat deze query het volgende oplevert:

{ _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)

Deze operator geeft de documenten terug die overeenkomen met de opgegeven waarden:

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

De waarde van een veld is gelijk aan een willekeurige waarde in de opgegeven matrix. Om bijvoorbeeld de documenten met de waarden “30” en “15” in de inventarisverzameling op te halen, zou je dit doen:

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

De uitvoer zou zijn:

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

Niet in ($nin)

Deze operator retourneert de documenten die niet overeenkomen met de gegeven waarden. Hier is de basissyntaxis van de operator $nin:

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

$nin selecteert de documenten waar:

  • de veldwaarde niet in de opgegeven matrix staat; of
  • het veld niet bestaat.

Als het veld arrays bevat, selecteert het arrays waar geen element gespecificeerd in de waarde-sectie aanwezig is. We willen bijvoorbeeld die documenten selecteren waarvan de hoeveelheid niet gelijk is aan 20 of 15.

Bovendien komt het ook overeen met documenten die geen hoeveelheidsveld hebben:

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

De uitvoer zou zijn:

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

Niet gelijk ($ne)

De operator $ne geeft de documenten terug waarin de opgegeven waarde niet gelijk is:

{ $ne: value } }

Stel bijvoorbeeld dat we alle documenten willen selecteren waarbij de hoeveelheid niet gelijk is aan 20:

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

De uitvoer zou zijn:

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

Uit bovenstaande uitvoer kunnen we zien dat de query documenten zal selecteren die geen hoeveelheidsveld hebben.

Element operators

De element query operators kunnen documenten identificeren aan de hand van de velden van het document. Element operators bestaan uit $exist en $type.

$exists

Deze operator komt overeen met documenten die een gespecificeerd veld hebben. Deze operator kent een booleaanse waarde die true of false kan zijn.

Als het is opgegeven als true, komt het overeen met de documenten die dat veld bevatten, inclusief documenten waarin de veldwaarde nul is. Als <boolean> false is, dan geeft de query alleen de documenten die het veld niet bevatten.

Hier is de standaard syntaxis:

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

Laten we een voorbeeld nemen waarbij we een verzameling gegevens hebben voor een array met de naam “bagofmarbles”, waarbij elke zak knikkers van verschillende kleuren bevat:

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

Laten we zeggen dat we een query willen die alleen die zakken oplevert waarin de rode knikkers voorkomen. Dit betekent dat we de booleaanse waarde moeten invoeren als true. Laten we eens kijken:

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

Het resultaat zou bestaan uit de documenten die het veld “red” bevatten, zelfs als de waarde null was. Het zou echter niet bestaan uit de documenten waarin het veld “red” niet eens bestaat:

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

Als we alleen die zakken wilden hebben waar rode knikkers niet eens als veld bestaan, kunnen we de onderstaande query invoeren:

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

De resultaten zouden bestaan uit die documenten die het veld “red” niet bevatten:

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

$type

Deze operator matcht documenten volgens het opgegeven veldtype. Dit is handig als je zeer ongestructureerde gegevens hebt, of als de datatypes niet voorspelbaar zijn. Deze veldtypen zijn gespecificeerde BSON-typen en kunnen worden gedefinieerd met een typenummer of een alias.

Dit is de algemene syntaxis voor $type:

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

Laten we zeggen dat we een adresboek hebben dat de onderstaande documenten bevat:

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

Bij het kijken naar bovenstaande documenten zie je dat de postcodes verschillende gegevenstypen hebben. Ze zijn lange, dubbele, gehele en string waarden.

Als we alleen die documenten willen die een bepaald datatype als postcode hebben – laten we in dit geval een string nemen – dan moeten we de volgende query invoeren in de compiler:

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

Dit zou de volgende documenten opleveren:

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

Daarnaast is er een type “number”, dat alle lange, gehele of dubbele waarden omvat als een array met een element van de gespecificeerde types:

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

Uitvoer:

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

Als de documenten een array-veldtype hebben, geeft de operator $type de documenten terug waarin ten minste één array-element overeenkomt met het aan de operator doorgegeven type.

Array operators

MongoDB bestaat ook uit array operators, om documenten met arrays te query’en.

Er zijn drie primaire operators: $all, $elemMatch en $size. Hieronder bespreken we ze elk in detail.

$all

De operator $all kiest de documenten waarin de waarde van een veld een array is met de opgegeven elementen:

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

Stel bijvoorbeeld dat we een verzameling documenten hebben voor een kledingwinkel, met wat je hieronder ziet als inventaris.

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

We willen alle documenten (in dit geval de kleding) uit de inventaris halen die gekoppeld zijn aan de tags “trendy” en “y2k”. De onderstaande query gebruikt de operator $all waarbij de waarde van het veld tags een array is waarvan de elementen “y2k” en “trendy” zijn:

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

Bovenstaande query levert het volgende op:

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

Uit het bovenstaande voorbeeld blijkt ook dat de operator $all gewoon dezelfde functie uitvoert als de operatie $and.

Als alternatief zouden we de onderstaande query kunnen gebruiken, die een soortgelijke uitvoer zou geven als de bovenstaande:

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

$elemMatch

De operator $elemMatch komt overeen met documenten die een matrixveld bevatten met ten minste één element dat overeenkomt met alle opgegeven querycriteria:

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

Hoewel we vergelijkingsoperators kunnen gebruiken zoals $lte en $gte, als we slechts een enkele queryvoorwaarde specificeren binnen $elemMatch, en de $not of de $ne operators niet gebruiken, kan het gebruik van $elemMatch worden weggelaten, omdat het in wezen dezelfde functie zou uitvoeren.

Er zijn nog een paar dingen om in gedachten te houden bij het gebruik van deze operator, voornamelijk:

  • Je kunt geen $where expression specificeren in een $elemMatch bewerking.
  • Je kunt geen $text query expression specificeren in een $elemMatch operatie.

We hebben bijvoorbeeld de volgende documenten in de verzameling leerlingresultaten:

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

De volgende query komt alleen overeen met die documenten waarvan de resultaten-array ten minste één element bevat dat zowel groter dan of gelijk is aan 90 als kleiner is dan 95:

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

Onze query levert het volgende document op, omdat het element 92 zowel groter dan of gelijk is aan 90 als kleiner is dan 95:

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

$size

De operator $size geeft die documenten terug waarvan de grootte van de matrix overeenkomt met het aantal elementen dat in het argument is opgegeven:

{ field: { $size: value } }

Hier volgt een voorbeeld:

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

Dit zou alle documenten in de opgegeven verzameling teruggeven waarbij het veld een array is met 2 elementen: { field: [ orange, apple] } en { field: [ blue, red] }, maar niet { field: blue} of { field: [ raspberry, lemon, grapefruit ] }.

Maar terwijl we de specifieke waarde kunnen invoeren als de grootte, kunnen we geen bereiken van waarden opgeven als de grootte.

Geospatiale operators

Met MongoDB kun je geospatiale gegevens opslaan in de vorm van GeoJSON types. GeoJSON is een open-standaard indeling gebaseerd op de JavaScript object notatie dat geografische kenmerken kan weergeven en niet-ruimtelijke attributen kan ondersteunen. Er zijn twee soorten geospatiale operators waar we het in dit artikel over zullen hebben: geometriespecificaties en query selectors.

$geometry

Deze operator vermeldt GeoJSON geometrie voor gebruik met de volgende ruimtelijke query operators: $geoIntersects, $geoWithin,$nearSphere, en $near. $geometry maakt gebruik van EPSG:4326 als standaard coördinaatreferentiesysteem (CRS).

Om GeoJSON objecten met het standaard CRS te vermelden, kun je gebruik maken van het volgende fragment voor $geometry:

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

Om een GeoJSON single-ringed polygon te mentionen met een tailored MongoDB CRS, kun je het volgende fragment gebruiken (je kunt dit alleen gebruiken voor $geoWithin en $geoIntersects):

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

$polygon

De $polygon operator kan worden gebruikt om een polygon te specificeren voor een geospatiale $geoWithin query op oude coördinatenparen. Deze query geeft dan paren terug die binnen de grenzen van de polygon vallen. Echter, $polygon zal geen GeoJSON objecten query’en. Om een polygon te definiëren, moet je een array van coördinaatpunten specificeren, als volgt:

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

Hier is het laatste punt impliciet verbonden met het eerste. Je kunt zoveel punten of zijden opgeven als je wilt.

De volgende query geeft bijvoorbeeld alle documenten met coördinaten binnen de polygon gedefinieerd door [0,0], [1,5], en [3,3]:

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

$geoWithin

Deze operator kan worden gebruikt om documenten met geospatiale gegevens te kiezen die volledig binnen een specifieke vorm liggen. De gespecificeerde vorm kan een GeoJSON polygon zijn, een GeoJSON polygon (met meerdere ringen of met één ring), of een vorm die kan worden gedefinieerd door oude coördinatenparen.

De $geoWithin operator maakt gebruik van de $geometry operator om het GeoJSON object te noemen.

Om de GeoJSON multipolygons of polygons via het standaard coördinatenreferentiesysteem (CRS) te vermelden, kun je de onderstaande syntaxis gebruiken:

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

Voor $geoWithin queries die de GeoJSON geometrieën vermelden met oppervlakten groter dan een enkele hemisfeer, zou het gebruik van het standaard CRS leiden tot queries voor de complementaire geometrieën.

Om een GeoJSON polygon met één enkele ring te mentionen met een custom MongoDB CRS, kun je gebruik maken van het hieronder genoemde prototype in de $geometry expression:

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

Het volgende voorbeeld kiest alle loc-gegevens die volledig binnen een GeoJSON polygon bestaan, waarbij de oppervlakte van de polygoon kleiner is dan de oppervlakte van een enkele hemisfeer:

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

$box

Je kunt $box gebruiken om een rechthoek te specificeren voor een geospatiale $geoWithin query om documenten te leveren die binnen de grenzen van de rechthoek liggen, volgens hun puntgebaseerde locatiegegevens. Als je $geoWithin gebruikt met de $box, krijg je documenten gebaseerd op de coördinaten van de query. In dit scenario vraagt $geoWithin geen GeoJSON vormen op.

Om de $box operator te gebruiken, moet je de rechterbovenhoek en de linkeronderhoek van de rechthoek vermelden in een array object:

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

De bovengenoemde query berekent de afstand door gebruik te maken van vlakke geometrie. De volgende query geeft alle documenten die binnen de box liggen met punten op: [0,0], [0,30], [30,0], [30,30]:

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

$nearSphere

Je kunt $nearSphere gebruiken om een punt te noemen waarvoor een geospatiale query de documenten teruggeeft van het dichtstbijzijnde naar het verste.

MongoDB gebruikt sferische geometrie om de afstanden te berekenen voor $nearSphere. Het zal een geospatiale index nodig hebben, als volgt:

  1. 2d index voor locatiegegevens beschreven als legale coördinatenparen. Om een 2d index op GeoJSON punten te gebruiken, moet je de index genereren op het coördinatenveld van het GeoJSON object.
  2. 2d index voor locatiegegevens beschreven als GeoJSON punten.

Om een GeoJSON punt te noemen, kun je gebruik maken van de volgende syntaxis:

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

Hier zijn $minDistance en $maxDistance optioneel. $minDistance kan de resultaten beperken tot de documenten die zich minstens op de opgegeven afstand van het centrum bevinden. Je kunt $maxDistance gebruiken voor beide indexen.

Beschouw nu een verzameling “plaatsen” die bestaat uit documenten met een location veld dat een 2dsphere index heeft. Het volgende voorbeeld zou de punten opleveren waarvan de locatie ten minste 2.000 meter en ten hoogste 6.000 meter van het door jou gekozen punt ligt, gerangschikt van dichtstbijzijnde naar verste:

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

$geoIntersects

Met de operator $geoIntersects kun je documenten selecteren waarvan de geospatiale gegevens een bepaald GeoJSON object snijden (d.w.z. waar de convergentie van het gespecificeerde object en de gegevens niet leeg is). Het maakt gebruik van de $geometry operator om het GeoJSON object te specificeren.

Om GeoJSON multipolygonen of polygonen via het standaard coördinaatreferentiesysteem (CRS) te vermelden, kun je de volgende syntaxis gebruiken:

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

De volgende instantie zal $geoIntersects gebruiken om alle loc-gegevens te kiezen die snijden met de polygon beschreven door de coördinaten-array:

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

$center

De operator $center noemt een cirkel voor een $geoWithin query die legacy coördinatenparen retourneert die binnen de grenzen van de cirkel liggen.

$center geeft geen GeoJSON objecten terug. Om gebruik te maken van de $center operator moet je een array specificeren die bevat:

  1. De straal van de cirkel, zoals gemeten in de door het coördinatensysteem gebruikte eenheden.
  2. De rastercoördinaten van het middelpunt van de cirkel.
{
  <location field> : {
      $geoWithin: { $center: [ [ <x> , <y> ] , <radius> ] }
   }
}

Het onderstaande voorbeeld geeft alle documenten met coördinaten die gevonden kunnen worden binnen de cirkel met het middelpunt op [2,3] en een straal van 40:

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

Projectie operators

Je kunt projectie operators gebruiken om de velden te noemen die door een operatie worden geretourneerd. Met MongoDB projectie operators kan de find() functie worden gebruikt met argumenten voor het filteren van gegevens. Dit helpt gebruikers om alleen de vereiste gegevensvelden uit een document te halen. Je kunt er dus transparante en beknopte gegevens mee projecteren zonder de algehele databaseprestaties aan te tasten.

$elemMatch (projectie)

De operator $elemMatch is verantwoordelijk voor het beperken van de inhoud van een veld uit de query-resultaten tot alleen het eerste element dat overeenkomt met de voorwaarde $elemMatch.

Hier zijn een paar dingen die je in gedachten moet houden voordat je $elemMatch gebruikt:

  • Vanaf MongoDB 4.4 retourneert de $elemMatch projectie van een bestaand veld, ongeacht de volgorde van de velden in het document, het veld dat volgt op de opname van andere bestaande velden.
  • Zowel de $elemMatch als de $ operator projecteren het eerste overeenkomende element uit een array op basis van een gespecificeerde voorwaarde. De $ operator zou het eerste overeenkomende array-element projecteren van elk document in een verzameling op basis van een voorwaarde uit het query statement, terwijl de $elemMatch projectie operator een expliciet condition argument neemt. Hiermee kun je projecteren op basis van een voorwaarde die niet in de query voorkomt, of als je moet projecteren op basis van verschillende velden in de embedded documenten van de array.

Je moet je ook bewust zijn van de volgende beperkingen voordat je de $elemMatch operator op je gegevens gebruikt:

  • Je kunt geen $text query-expression noemen binnen een $elemMatch operator.
  • db.collection.find() bewerkingen op views ondersteunen de $elemMatch projectie operator niet.

Het volgende voorbeeld over de $elemMatch projectie operator gaat uit van een collectie schools met de volgende documenten:

{
 _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 dit geval vraagt de find() bewerking naar alle documenten waarin de waarde van het veld postcode 63110 is. De $elemMatch projectie zou alleen het eerste overeenkomende element van de students array teruggeven waar het veld school de waarde 103 heeft:

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

Zo zou het resultaat eruit zien:

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

$slice (projectie)

De operator $slice projectie kan worden gebruikt om het aantal elementen in een array op te geven dat in het query-resultaat moet worden teruggegeven:

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

Het kan ook op deze manier worden uitgedrukt:

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

Om hetzelfde te demonstreren kun je een voorbeeldverzameling van tweets maken met de volgende documenten:

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

De volgende bewerking zou de $slice projectie operator gebruiken op de tweets array om de array met zijn eerste twee elementen terug te geven. Als een array minder dan twee elementen bevat, worden alle elementen in de array teruggegeven:

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

Die bewerking zou de volgende documenten teruggeven:

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

$ (projectie)

De positionele operator $ beperkt de inhoud van een array om het eerste element terug te geven dat overeenkomt met de zoekvoorwaarde van die array. Je kunt $ gebruiken in het projectiedocument van de methode find() of de methode findOne() als je slechts één bepaald array-element in gekozen documenten nodig hebt.

Zo ziet de syntaxis voor de $ operator eruit:

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

In dit voorbeeld bestaat de verzameling students uit de volgende documenten:

{ "_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 de volgende query retourneert de projectie { "grades.$": 1 } alleen het eerste element groter dan of gelijk aan 89 voor het veld grades:

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

Deze bewerking levert de volgende documenten op:

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

Evaluatie operators

Je kunt MongoDB evaluatie operators gebruiken om de algemene gegevensstructuur of individuele velden in een document te meten.

Laten we eens kijken naar enkele veel voorkomende MongoDB evaluatie operators.

$mod

Je kunt deze operator gebruiken om documenten te matchen waar de waarde van een gespecificeerd veld gelijk is aan de rest na gedeeld te zijn door een gespecificeerde waarde:

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

Stel je hebt een tabel met auto’s van verschillende merken die je in je showroom hebt staan. De volgende query zou je alle automerken geven waarvan het voorraadnummer een veelvoud is van 250.

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

$jsonSchema

Met $jsonSchema kun je de documenten matchen die overeenkomen met het opgegeven JSON schema. MongoDB’s implementatie van het JSON schema bevat de toevoeging van het bsonType keyword, waarmee je alle BSON types kunt gebruiken binnen de $jsonSchema operator.

bsonType kan dezelfde string aliassen accepteren die je zou gebruiken voor de type operator. Zo zou $jsonSchema’s syntax eruit zien:

{ $jsonSchema: <JSON Schema object> }

Hier is het JSON schema object geformatteerd op basis van het ontwerp 4 van de JSON schema standaard:

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

Hier is een voorbeeld om te demonstreren hoe $jsonSchema werkt:

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

Je kunt $jsonSchema ook gebruiken in een documentvalidator om het opgegeven schema af te dwingen bij update- en invoegbewerkingen:

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

Bedenk dat er verschillende zaken zijn die niet ondersteund worden door de $jsonSchema operator:

  1. Het integer type. Je moet het BSON type long of int gebruiken met het bsonType keyword.
  2. Onbekende keywords.
  3. Het koppelen van properties en de hypermedia van JSON schema, samen met het gebruik van JSON referenties en JSON pointers.

$text

De operator $text zoekt naar een tekst binnen de inhoud van het opgegeven veld, geïndexeerd met een text index:

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

In dit geval zal het volgende codefragment de tabel doorzeven om alle auto’s met de tekst “Porsche” erin uit te filteren:

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

$regex

De operator $regex biedt mogelijkheden voor reguliere expressions om patroonmatches in queries toe te passen. MongoDB maakt gebruik van reguliere expressions die compatibel zijn met Perl:

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

Het volgende voorbeeld zou helpen om alle auto’s uit te filteren waar de string “$78900” in voorkomt:

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

$expr

Met de operator $expr kun je aggregatie-expressions gebruiken in de querytaal:

{ $expr: { <expression> } }

Je kunt ook $expr gebruiken om query-expressions te bouwen die velden uit hetzelfde document vergelijken in een $match stadium. Als de $match stap toevallig deel uitmaakt van een $lookup stap, kan $expr velden vergelijken met behulp van let variabelen.

$where

Je kunt de $where operator gebruiken om een string met een volledige JavaScript functie of een JavaScript expression door te geven aan het query systeem. De $where operator biedt meer flexibiliteit, maar vereist dat de database de JavaScript functie of expression verwerkt voor elk document in de collectie. Je kunt naar dit document verwijzen in de JavaScript functie of expression door obj of this te gebruiken.

Hier is een voorbeeld van de syntaxis:

{ $where: <string|JavaScript Code> }

Er zijn een paar belangrijke overwegingen om in gedachten te houden voordat we in een voorbeeld duiken tijdens het gebruik van de $where operator:

  • Je moet de $where query operator alleen gebruiken voor documenten op het hoogste niveau. De $where query operator werkt niet in een nested document, zoals in een $elemMatch query.
  • In het algemeen moet je $where alleen gebruiken als je je query niet via een andere operator kunt uitdrukken. Als je $where moet gebruiken, zorg er dan voor dat je tenminste één andere standaard query operator toevoegt om de resultatenverzameling te filteren. Onafhankelijk gebruik van $where vereist een verzamelscan voor een goede uitvoering.

Hier is een voorbeeld om dit te illustreren:

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

Bitwise operators

Bitwise operators geven gegevens terug op basis van bitpositievoorwaarden. Eenvoudig gezegd worden ze gebruikt om numerieke of binaire waarden te matchen waarin elke bit van een set bitposities de waarde 1 of 0 heeft.

$bitsAllSet

Deze operator komt overeen met alle documenten waarin alle door de query opgegeven bitposities in het veld zijn ingesteld (d.w.z. 1):

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

De veldwaarde moet ofwel een BinData instantie of numeriek zijn voor $bitsAllSet om overeen te komen met het huidige document.

In het volgende voorbeeld maken we gebruik van een verzameling met de volgende documenten:

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

De hieronder genoemde query zal de $bitsAllSet operator gebruiken om te testen of veld a bits heeft ingesteld op positie 1 en positie 5, waarbij de minst significante bit op positie 0 zou staan:

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

Deze query zou overeenkomen met de volgende documenten:

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

$bitsAllClear

De operator $bitsAllClear komt overeen met documenten waarin alle door de query opgegeven bitposities clear of 0 zijn:

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

We gebruiken hier het voorbeeld van $bitsAllSet om het gebruik van $bitsAllClear te demonstreren. De volgende query zou deze operator gebruiken om te controleren of in veld a de bits op de posities 1 en 5 leeg zijn:

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

Deze query zou overeenkomen met de volgende documenten:

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

Meta operators

Er zijn verschillende query modifiers waarmee je het gedrag of de uitvoer van een query in MongoDB kunt wijzigen. De driver-interfaces kunnen cursormethoden bieden die ze voor jouw gebruik wrappen.

$hint

MongoDB deprecieerde $hint sinds v3.2. Maar deze operator kan nog steeds beschikbaar zijn voor MongoDB drivers zoals Go, Java, Scala, Ruby, Swift, enz. Het kan de query optimizer dwingen om een specifieke index te gebruiken om de query te fulfillen, die dan per document of per indexnaam kan worden genoemd.

Je kunt de $hint operator ook gebruiken om indexeringsstrategieën en queryprestaties te testen. Neem bijvoorbeeld de volgende bewerking:

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

Deze bewerking zou alle documenten binnen de verzameling genaamd users teruggeven door gebruik te maken van de index op het veld age.

Je kunt ook een hint noemen door een van de volgende vormen te gebruiken:

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

Als er een indexfilter bestaat voor de queryvorm, zou MongoDB de $hint gewoon negeren.

$comment

Met de operator $comment kun je een comment toevoegen aan een query in elke context waarin $query kan voorkomen. Omdat comments propageren in het de profile log, kan het toevoegen van comments het interpreteren en traceren van je profiel vergemakkelijken.

Je kunt $comment op drie manieren gebruiken:

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

Als je commentaar wilt toevoegen aan query expressions in andere contexten, zoals met db.collection.update(), maak dan gebruik van de $comment query operator in plaats van de meta operator.

$max

Je kunt een $max waarde noemen om de exclusieve bovengrens voor een bepaalde index te specificeren om de resultaten van find() te beperken. Deze operator specificeert de bovengrens voor alle sleutels van een specifieke volgorde in de index.

Mongosh geeft je de volgende max() wrapper methode:

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

Je kunt ook $max noemen met de volgende twee vormen:

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

Als je bijvoorbeeld de exclusieve bovengrens wilt specificeren, houd dan rekening met de volgende bewerkingen op een verzameling met de naam verzameling die een index { age: 1 } bevat:

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

Deze bewerking beperkt de query tot die documenten waarin het veld leeftijd minder dan 100 is en dwingt een queryplan af dat de index { age: 1 } scant van minKey tot 100.

$explain

Deze operator geeft informatie over het queryplan. Het geeft een document terug dat de indexen en processen beschrijft die gebruikt worden om de query te retourneren. Dit kan handig zijn als je een query probeert te optimaliseren.

Je kunt de operator $explain in een van de volgende vormen noemen:

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

Best practices voor MongoDB operators

In deze paragraaf bekijken we een paar van de best practices bij het gebruik van deze MongoDB operators.

Embedden en refereren

Embedden is een natuurlijke uitbreiding van datamodellering. Hiermee kun je application joins vermijden, wat updates en queries kan verminderen.

Je kunt gegevens met een 1:1 relatie inbedden binnen een enkel document. Gegevens met een veel:1 relatie waarin “veel” objecten voorkomen met hun bovenliggende documenten kunnen echter ook goede kandidaten zijn.

Het opslaan van dit soort gegevens in hetzelfde document lijkt een verstandige keuze. Embedden levert echter betere prestaties voor leesbewerkingen met dit soort gegevenslocaliteit.

Gegevensmodellen die zijn embed kunnen ontwikkelaars ook helpen om geassocieerde gegevens in een enkele schrijfoperatie bij te werken. Dit werkt omdat het schrijven van een enkel document transactioneel is.

Je zou het gebruik van referencing moeten overwegen voor de volgende scenario’s:

  • Wanneer je een documentsegment bijwerkt en het steeds langer wordt, terwijl de rest van het document statisch is.
  • Wanneer een document wordt opgevraagd, maar gegevens bevat die zelden worden gebruikt. Embedden zou de in-memory vereisten alleen maar vergroten, dus is referencing zinvoller.
  • Wanneer de documentgrootte de MongoDB documentlimiet van 16MB overschrijdt. Dit kan gebeuren bij het modelleren van veel:1 relaties (bijvoorbeeld medewerkers:afdeling).

Profilering en querypatronen onderzoeken

Voor de meeste ontwikkelaars is de eerste stap in het optimaliseren van de prestaties het begrijpen van de werkelijke en verwachte querypatronen. Als je de querypatronen van je applicatie goed genoeg kent, kun je je gegevensmodel maken en geschikte indices kiezen.

MongoDB ontwikkelaars hebben toegang tot diverse krachtige hulpmiddelen waarmee ze de prestaties kunnen verbeteren. Maar dat betekent niet dat queryprofielen en patronen genegeerd kunnen worden.

Een eenvoudige manier om de prestaties te verbeteren is bijvoorbeeld door je querypatronen te analyseren en te begrijpen waar je gegevens kunt embedden. Andere manieren om de prestaties van MongoDB te verbeteren na het identificeren van je belangrijkste querypatronen zijn:

  • Ervoor zorgen dat je indices hebt op alle velden waartegen je query’s uitvoert.
  • De resultaten van frequente subqueries op documenten opslaan om de leesbelasting te verminderen.
  • In je logboeken kijken naar trage queries en dan je indexen controleren.

Gegevensindexering en -modellering herzien

Terwijl je je gegevensmodel maakt, beslis je hoe je relaties tussen gegevens gaat modelleren. Kiezen wanneer je een document embedt versus het maken van een reference over afzonderlijke documenten in verschillende verzamelingen, bijvoorbeeld, is een voorbeeld van een toepassingsspecifieke overweging.

Een groot voordeel van JSON documenten is dat ze ontwikkelaars in staat stellen gegevens te modelleren op basis van de eisen van de toepassing. Door subdocumenten en arrays te nesten kun je complexe relaties tussen gegevens modelleren door gebruik te maken van eenvoudige tekstdocumenten.

Je kunt MongoDB ook gebruiken om het volgende te modelleren:

  • Geospatiale gegevens
  • Tabulaire, platte en kolomstructuren
  • Eenvoudige sleutel-waarde paren
  • Tijdreeksgegevens
  • Randen en knopen van verbonden grafiekgegevensstructuren en dergelijke

Sharding en replicatie monitoren

Replicatie kan cruciaal zijn voor het verbeteren van de prestaties, omdat het de beschikbaarheid van gegevens vergroot door horizontale schaling. Replicatie kan leiden tot betere prestaties en meer veiligheid door redundantie.

Prestatiemonitoring kan gedoe opleveren, omdat dat extra middelen en tijd vergt om een soepele werking te garanderen. Je kunt gebruik maken van op de markt verkrijgbare tools voor prestatiemonitoring die aan je specifieke behoeften voldoen.

Zo kan Kinsta APM tijdgestampte informatie verzamelen over de MySQL databasequeries van je WordPress site, PHP processen, externe HTTP calls en nog veel meer. Je kunt deze gratis tool ook gebruiken om het volgende te debuggen:

  • Lange API calls
  • Lange externe URL queries
  • Trage databasequeries, om er een paar te noemen.

In MongoDB kan replicatie worden bereikt door middel van replicasets waarmee ontwikkelaars gegevens van een primaire node of server kunnen kopiëren over meerdere secondaries. Dit laat je replicatie sommige queries uitvoeren op secondaries in plaats van op de primary, waardoor contention wordt vermeden en een betere load balancing ontstaat.

Sharded clusters in MongoDB zijn een andere manier om de prestaties te verbeteren. Net als replicatie kan sharding worden gebruikt om grote gegevenssets over meerdere servers te verdelen.

Door gebruik te maken van een shard key kunnen ontwikkelaars shards of stukken data kopiëren over meerdere servers. Deze servers kunnen samenwerken om alle gegevens te gebruiken.

Sharding heeft zo zijn voordelen, waaronder horizontale schaling voor schrijven/lezen, hogere beschikbaarheid en grotere opslagcapaciteit.

Geheugengebruik bepalen

MongoDB presteert het best als de werkset van een toepassing (d.w.z. veelgebruikte gegevens en indices) zonder problemen in het geheugen past. Hoewel andere factoren bepalend zijn voor de prestaties, is de grootte van het RAMgeheugen het belangrijkst voor de grootte van de instantie.

Als de werkset van een toepassing in het RAM past, moet de leesactiviteit van de schijf laag zijn. Maar als je werkset het RAM van de instance server of grootte overschrijdt, zal de leesactiviteit omhoog schieten.

Als je dit ziet gebeuren, kun je het probleem misschien oplossen door over te stappen op een grotere instance met meer geheugen.

Plaats velden met meerdere waarden aan het eind

Als je een aantal velden indexeert, en een van de velden die je wilt query’en gebruikt een van die “multi-value” operators, dan moet je die aan het eind van de index zetten. Je moet de index zo rangschikken dat de opgevraagde velden voor exacte waarden eerst komen en de “multi-value” operators als laatste in de index.

Een uitzondering hierop zou sorteren op de velden zijn. Plaats deze tussen de “multi-value” en exacte velden om de hoeveelheid in-memory sorteren die nodig is te verminderen.

Samenvatting

Voor MongoDB is snelheid cruciaal. Om queries snel terug te sturen, gebruikt MongoDB operators om wiskundige of logische taken uit te voeren. Kort door de bocht: het begrijpen van MongoDB operators is de sleutel tot het beheersen van MongoDB.

Dit artikel belicht enkele van de belangrijkste MongoDB operators die je op je gegevens kunt gebruiken, zoals vergelijkingsoperators, logische operators, meta-operators en projectie-operators, om er een paar te noemen. Het helpt je ook begrijpen hoe je MongoDB operators kunt gebruiken en de best practices waarmee je er het meeste uit kunt halen.

Welke van de operators gebruik jij het vaakst, en waarom? Deel het hieronder in de comments – we horen graag je gedachten!

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.