In qualsiasi azienda, i dati sono la vostra risorsa più importante. Analizzando i dati, potete prendere decisioni sulle tendenze e sui comportamenti dei clienti. Questo aumenta la redditività dell’azienda e l’efficacia del processo decisionale.

Senza un software di database, un compito semplice come trovare la media di tutti i valori in un sistema pieno di record sarebbe noioso. Per fortuna i database hanno reso l’analisi dei dati più semplice e veloce grazie a funzioni e operatori.

Questo articolo farà luce sugli operatori utilizzati nel database MongoDB.

Cosa Sono gli Operatori di MongoDB?

MongoDB è un database NoSQL che gestisce informazioni orientate ai documenti.

Una delle caratteristiche principali di MongoDB è la sua velocità. Per rendere le query più veloci, MongoDB può usare degli operatori per eseguire funzioni specifiche.

Gli operatori sono simboli speciali che aiutano i compilatori a eseguire operazioni matematiche o logiche. MongoDB offre diversi tipi di operatori per interagire con il database.

Tipi di Operatori di MongoDB

Esistono nove tipi di operatori, ognuno dei quali prende il nome dalla sua funzione. Per esempio, gli operatori logici utilizzano operazioni logiche. Per eseguirli, dovete utilizzare una parola chiave specifica e seguire la sintassi. Tuttavia, sono abbastanza facili da seguire!

Alla fine dell’articolo, avrete appreso le basi di ogni operatore e le sue funzioni.

Operatori Logici

Gli operatori logici sono spesso utilizzati per filtrare i dati in base alle condizioni date. Consentono inoltre di valutare numerose condizioni, di cui parleremo in dettaglio.

Di seguito sono elencati alcuni operatori logici che potete usare:

$and

Una condizione “and” esegue un’operazione logica “and” su un array di due o più espressioni. Seleziona i documenti in cui tutte le condizioni delle espressioni sono soddisfatte.

Questa è la sintassi standard dell’espressione $and:

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

$or

Una condizione “or” esegue un’operazione logica “or” su un array di due o più espressioni. Seleziona i documenti in cui almeno una delle espressioni è vera.

Questa è la sintassi standard dell’espressione $or:

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

Per esempio, se vogliamo selezionare i documenti in cui il prezzo è di 10 dollari o la quantità è inferiore a 15, possiamo inserire la seguente query:

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

Non è necessario limitare l’espressione a due criteri: possiamo aggiungerne altri. Per esempio, la seguente query seleziona i documenti il cui prezzo è pari a 10 dollari, la cui quantità è inferiore a 15 o il cui tag è stazionario:

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

Quando si eseguono queste clausole, MongoDB esegue una scansione della collezione o una scansione dell’indice. Se tutti gli indici supportano le clausole, allora MongoDB utilizza gli indici per verificare un’espressione $or. In caso contrario, utilizza una scansione della collezione.

Tuttavia, se volete verificare i criteri nello stesso campo, potreste voler usare l’operatore $in piuttosto che l’operatore $or. Per esempio, se volete ottenere una raccolta di documenti in cui la quantità sia 10 o 20, dovrete eseguire la seguente query $in:

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

Parleremo più avanti dell’operatore $in.

$nor

Questo operatore esegue un’operazione logica “nor” su un array utilizzando una o più espressioni. Quindi seleziona i documenti che non soddisfano le espressioni della query. In parole povere, fa l’opposto della condizione $or.

Questa è la sintassi generale:

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

Consideriamo la seguente query:

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

Questa query seleziona i documenti che contengono:

  • un valore del campo prezzo non uguale a $3,99 e un valore di vendita non uguale a true; oppure
  • un valore del campo prezzo non uguale a $3,99 e un campo vendita vuoto o assente; oppure
  • nessun campo prezzo e un campo vendita non uguale a true; oppure
  • né il campo prezzo né il campo vendita popolati o presenti.

$not

Questo operatore esegue un’operazione logica “not” su un array per l’espressione specificata. Seleziona quindi i documenti che non corrispondono alle espressioni della query. Questo include i documenti che non contengono il campo.

Questa è la sintassi generale:

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

Per esempio, prendiamo la seguente query:

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

Questa query selezionerà i documenti che contengono:

  • un campo prezzo il cui valore è maggiore o uguale a $3,99; e
  • un campo prezzo non popolato o inesistente.

Operatori di Confronto

Gli operatori di confronto si possono usare per confrontare i valori di uno o più documenti.

Di seguito è riportato un esempio di codice di una semplice raccolta di inventari per un supermercato:

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

Utilizzeremo questo esempio per descrivere nel dettaglio ogni operatore di confronto.

Uguale a ($eq)

Questo operatore viene soddisfatto se i valori che sono uguali al valore dato:

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

Per esempio, se vogliamo recuperare un documento specifico dalla raccolta dell’inventario con il valore esatto di quantità “20”, dovremo inserire il seguente comando:

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

La query restituirà quanto segue:

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

Maggiore di ($gt)

Questo operatore viene soddisfatto se i valori sono maggiori del valore indicato:

{ field: { $gt: value } }

In questo esempio, recuperiamo i documenti la cui quantità è superiore a 15:

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

La query restituirà quanto segue:

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

Meno di ($lt)

Questo operatore viene soddisfatto se i valori sono inferiori al valore fornito:

{ field: { $lt: value } }

Troviamo i documenti con una quantità inferiore a 25:

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

La query restituirà quanto segue:

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

Maggiore o Uguale a ($gte)

Questo operatore viene soddisfatto quando i valori sono maggiori o uguali al valore indicato:

{ field: { $gte: value } }

In questo esempio, recuperiamo i documenti la cui quantità è maggiore o uguale a 25:

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

Questa query restituirà quanto segue:

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

Minore o Uguale a ($lte)

Questo operatore viene soddisfatto solo se i valori sono minori o uguali al valore indicato:

{ field: { $lte: value } }

Troviamo i documenti con una quantità minore o uguale a 25.

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

Possiamo aspettarci che questa query restituisca quanto segue:

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

Questo operatore restituisce i documenti che corrispondono ai valori specificati:

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

Il valore di un campo è uguale a qualsiasi valore dell’array specificato. Per esempio, per recuperare i documenti con i valori “30” e “15” nella raccolta dell’inventario, dovete procedere in questo modo:

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

L’output sarebbe:

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

Not in ($nin)Questo operatore restituisce i documenti che non corrispondono ai valori indicati. Ecco la sintassi di base dell’operatore $nin:

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

$nin seleziona i documenti dove:

  • il valore del campo non si trova nell’array specificato; oppure
  • il campo non esiste.

Se il campo contiene degli array, selezionerà gli array in cui non è presente alcun elemento specificato nella sezione del valore. Per esempio, vogliamo selezionare i documenti in cui la quantità non è uguale a 20 o a 15.

Inoltre, seleziona anche i documenti che non hanno un campo quantità:

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

L’output sarebbe:

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

Non uguale ($ne)

L’operatore $ne restituisce i documenti in cui il valore specificato non è uguale:

{ $ne: value } }

Per esempio, supponiamo di voler selezionare tutti i documenti in cui la quantità non è uguale a 20:

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

L’output sarebbe:

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

Dall’output precedente, possiamo vedere che la query selezionerà i documenti che non hanno un campo quantità.

Operatori degli Elementi

Gli operatori di query elementari possono identificare i documenti utilizzando i campi del documento. Gli operatori di elemento sono costituiti da $exist e $type.

$exists

Questo operatore corrisponde ai documenti che hanno un campo specificato. Questo operatore ha un valore booleano che può essere true o false.

Se il valore specificato è true, corrisponde ai documenti che contengono quel campo, compresi i documenti in cui il valore del campo è nullo. Se <boolean> è false, la query restituisce solo i documenti che non contengono il campo.

Ecco la sintassi standard:

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

Facciamo un esempio in cui abbiamo una raccolta di dati per un array chiamato “sacchetto di biglie”, dove ogni sacchetto contiene biglie di colori diversi:

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

Supponiamo di volere una query che restituisca solo i sacchetti in cui sono presenti biglie rosse. Questo significa che dovremo inserire il valore booleano come true. Diamo un’occhiata:

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

I risultati sarebbero costituiti dai documenti che contengono il campo “red”, anche se il valore fosse null. Tuttavia, non sarebbero costituiti dai documenti in cui il campo “red” non esiste:

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

Se vogliamo solo le buste in cui le biglie rosse non esistono nemmeno come campo, possiamo inserire la seguente query:

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

I risultati saranno costituiti dai documenti che non contengono il campo “red”:

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

$type

Questo operatore abbina i documenti in base al tipo di campo specificato. È utile quando avete dati molto poco strutturati o quando i tipi di dati non sono prevedibili. Questi tipi di campo sono tipi BSON specificati e possono essere definiti sia dal numero del tipo che dall’alias.

Questa è la sintassi generale di $type:

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

Supponiamo di avere una rubrica contenente i documenti seguenti:

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

Osservando i documenti di cui sopra, il codice postale ha diversi tipi di dati. Si tratta di valori long, double, integer e string.

Se vogliamo ottenere solo i documenti che hanno un determinato tipo di dato come codice postale – prendiamo per esempio una stringa – dobbiamo inserire la seguente query nel compilatore:

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

Questo restituirebbe i seguenti documenti:

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

Inoltre, esiste un tipo “number” che include tutti i valori long, integer o double come array contenente un elemento dei tipi specificati:

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

Output:

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

Se i documenti hanno un tipo di campo array, l’operatore $type restituisce i documenti in cui almeno un elemento dell’array corrisponde al tipo passato all’operatore.

Operatori di Array

MongoDB dispone anche di operatori di array, per interrogare documenti contenenti array.

Esistono tre operatori principali: $all, $elemMatch e $size. Di seguito ne parleremo in dettaglio.

$all

L’operatore $all sceglie i documenti in cui il valore di un campo è un array contenente gli elementi specificati:

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

Per esempio, supponiamo di avere una raccolta di documenti per un negozio di abbigliamento, con i seguenti elementi sotto l’inventario.

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

Vogliamo recuperare tutti i documenti (in questo caso, i vestiti) dall’inventario che sono collegati ai tag “trendy” e “y2k”. La seguente query utilizza l’operatore $all dove il valore del campo tags è un array i cui elementi includono “y2k” e “trendy”:

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

La query di cui sopra restituisce quanto segue:

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

Dall’esempio precedente, scopriamo che l’operatore $all svolge semplicemente la stessa funzione dell’operazione $and.

In alternativa, possiamo usare la seguente query che darà un risultato simile a quello di cui sopra:

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

$elemMatch

L’operatore $elemMatch corrisponde ai documenti che contengono un campo array con almeno un elemento che corrisponde a tutti i criteri di ricerca specificati:

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

Sebbene si possano utilizzare operatori di confronto come $lte e $gte, se si specifica una sola condizione di query all’interno di $elemMatch e non si utilizzano gli operatori $not o $ne, l’utilizzo di $elemMatch può essere omesso in quanto svolge essenzialmente la stessa funzione.

Ci sono alcune altre cose da tenere a mente quando si utilizza questo operatore, soprattutto:

  • Non potete specificare un’espressione $where in un’operazione $elemMatch.
  • Non potete specificare un’espressione di query $text in un’operazione $elemMatch.

Per esempio, abbiamo i seguenti documenti nella raccolta dei risultati degli studenti:

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

La seguente query corrisponde solo ai documenti in cui l’array dei risultati contiene almeno un elemento maggiore o uguale a 90 e inferiore a 95:

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

La nostra query restituisce il seguente documento, poiché l’elemento 92 è maggiore o uguale a 90 e inferiore a 95:

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

$size

L’operatore $size restituisce i documenti in cui la dimensione dell’array corrisponde al numero di elementi specificato nell’argomento:

{ field: { $size: value } }

Ecco un esempio:

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

Questo restituisce tutti i documenti della collezione specificata in cui il campo è un array con 2 elementi: { field: [ orange, apple] } e { field: [ blue, red] }, ma non { field: blue} o { field: [ raspberry, lemon, grapefruit ] }.

Tuttavia, mentre possiamo inserire un valore specifico come dimensione, non possiamo specificare intervalli di valori come dimensione.

Operatori Geospaziali

MongoDB vi permette di memorizzare dati geospaziali sotto forma di GeoJSON. GeoJSON è un formato open-standard basato sulla notazione a oggetti di JavaScript che può rappresentare caratteristiche geografiche e supportare attributi non spaziali. Ci sono due tipi di operatori geospaziali di cui parleremo in questo articolo: gli specificatori di geometria e i selettori di query.

$geometry

Questo operatore indica la geometria GeoJSON da utilizzare con i seguenti operatori di query geospaziali: $geoIntersects, $geoWithin,$nearSphere, e $near. $geometry utilizza EPSG:4326 come sistema di riferimento delle coordinate (CRS) predefinito.

Per menzionare gli oggetti GeoJSON con il CRS predefinito, potete usare il seguente snippet per $geometry:

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

Per menzionare un poligono GeoJSON con un CRS personalizzato di MongoDB, potete usare il seguente snippet (potete usarlo solo per $geoWithin e $geoIntersects):

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

$polygon

L’operatore $polygon può essere utilizzato per specificare un poligono per una query geospaziale $geoWithin su coppie di coordinate legacy. Questa query restituirà le coppie che rientrano nei confini del poligono. Tuttavia, $polygon non eseguirà alcuna query su oggetti GeoJSON. Per definire un poligono, dovete specificare un array di punti di coordinate come segue:

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

In questo caso, l’ultimo punto è implicitamente collegato al primo. Potete indicare tutti i punti o i lati che volete.

Per esempio, la seguente query restituirà tutti i documenti che hanno coordinate comprese nel poligono definito da [0,0], [1,5] e [3,3]:

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

$geoWithin

Questo operatore può essere utilizzato per scegliere i documenti con dati geospaziali che sono completamente contenuti in una forma specifica. La forma specificata può essere un multipoligono GeoJSON, un poligono GeoJSON (sia a più anelli che a singolo anello) o una forma che può essere definita da coppie di coordinate legacy.

L’operatore $geoWithin sfrutterà l’operatore $geometry per citare l’oggetto GeoJSON.

Per menzionare i multipoligoni o i poligoni GeoJSON tramite il Sistema di Riferimento di Coordinate (CRS) predefinito, potete usare la sintassi indicata di seguito:

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

Per le query di $geoWithin che menzionano le geometrie GeoJSON con aree più grandi di un singolo emisfero, l’uso del CRS predefinito porterà a query per le geometrie complementari.

Per menzionare un poligono GeoJSON con un singolo emisfero con un CRS MongoDB personalizzato, potete utilizzare il prototipo menzionato di seguito nell’espressione $geometry:

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

Il seguente esempio preleva tutti i dati loc che esistono completamente all’interno di un poligono GeoJSON, la cui area è inferiore a quella di un singolo emisfero:

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

$box

Potete usare $box per specificare un rettangolo per una query geospaziale $geoWithin per fornire i documenti che si trovano all’interno dei confini del rettangolo, in base ai loro dati di localizzazione puntuali. Quando usate $geoWithin con $box, otterrete documenti basati sulle coordinate della query. In questo scenario, $geoWithin non interrogherà nessuna forma GeoJSON.

Per sfruttare l’operatore $box, dovete menzionare gli angoli superiore destro e inferiore sinistro del rettangolo in un oggetto array:

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

La query di cui sopra calcolerà la distanza utilizzando la geometria planare (piatta). La seguente query restituirà tutti i documenti che si trovano all’interno del rettangolo i cui punti sono: [0,0], [0,30], [30,0], [30,30]:

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

$nearSphere

Potete usare $nearSphere per indicare un punto per il quale una query geospaziale restituisce i documenti dal più vicino al più lontano.

MongoDB usa la geometria sferica per calcolare le distanze per $nearSphere. Avrà bisogno di un indice geospaziale come segue:

  1. indice 2d per i dati sulla posizione descritti come coppie di coordinate legacy. Per sfruttare un indice 2d sui punti GeoJSON, dovete generare l’indice sul campo delle coordinate dell’oggetto GeoJSON.
  2. indice 2dsphere per i dati di localizzazione descritti come punti GeoJSON.

Per menzionare un punto GeoJSON, potete utilizzare la seguente sintassi:

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

In questo caso, $minDistance e $maxDistance sono opzionali. $minDistance può limitare i risultati ai documenti che si trovano almeno alla distanza specificata dal centro. Potete usare $maxDistance per entrambi gli indici.

Ora, considerate una collezione di “luoghi” che consiste in documenti con un campo di posizione che ha un indice 2dsphere. L’esempio seguente restituisce i punti la cui posizione dista almeno 2.000 metri e al massimo 6.000 metri dal punto scelto, ordinati dal più vicino al più lontano:

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

$geoIntersects

L’operatore $geoIntersects vi permette di selezionare i documenti i cui dati geospaziali si intersecano con un particolare oggetto GeoJSON (cioè dove la convergenza dell’oggetto specificato e dei dati non è vuota). Sfrutta l’operatore $geometry per specificare l’oggetto GeoJSON.

Per citare i multipoligoni o i poligoni GeoJSON attraverso il sistema di riferimento delle coordinate (CRS) predefinito, potete utilizzare la seguente sintassi:

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

La seguente istanza utilizzerà $geoIntersects per selezionare tutti i dati loc che si intersecano con il poligono descritto dall’array di coordinate:

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

$center

L’operatore $center menziona un cerchio per una query $geoWithin che restituisce le coppie di coordinate legacy che si trovano entro i confini del cerchio.

$center non restituisce oggetti GeoJSON. Per sfruttare l’operatore $center, dovete specificare un array che contenga:

  1. Il raggio del cerchio, misurato nelle unità utilizzate dal sistema di coordinate.
  2. Le coordinate della griglia del punto centrale del cerchio.
{
  <location field> : {
      $geoWithin: { $center: [ [ <x> , <y> ] , <radius> ] }
   }
}

L’esempio riportato di seguito restituirà tutti i documenti le cui coordinate si trovano all’interno del cerchio centrato su [2,3] e con raggio 40:

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

Operatori di Proiezione

Potete usare gli operatori di proiezione per menzionare i campi restituiti da un’operazione. Gli operatori di proiezione di MongoDB consentono di utilizzare la funzione find() con argomenti di filtraggio dei dati. In questo modo gli utenti possono estrarre da un documento solo i campi di dati richiesti. Quindi, vi permette di proiettare dati trasparenti e concisi senza influire sulle prestazioni complessive del database.

$elemMatch (proiezione)

L’operatore $elemMatch è responsabile di limitare il contenuto di un campo dei risultati della query in modo che contenga solo il primo elemento che corrisponde alla condizione $elemMatch.

Ecco alcune cose che dovete tenere a mente prima di usare $elemMatch:

  • Da MongoDB 4.4, indipendentemente dall’ordine dei campi nel documento, la proiezione $elemMatch di un campo esistente restituisce il campo dopo l’inclusione di altri campi esistenti.
  • Entrambi gli operatori $elemMatch e $ proiettano il primo elemento corrispondente di un array in base a una condizione specificata. L’operatore $ proietta il primo elemento corrispondente di un array da ogni documento di una collezione in base a una condizione dell’istruzione di query, mentre l’operatore di proiezione $elemMatch richiede un argomento esplicito di condizione. Questo vi permette di proiettare in base a una condizione non presente nella query o se avete bisogno di proiettare in base a vari campi nei documenti incorporati nell’array.

Prima di usare l’operatore $elemMatch sui vostri dati, dovete tenere presente le seguenti restrizioni:

  • Non potete menzionare un’espressione di query $text all’interno di un operatore $elemMatch.
  • Le operazioni db.collection.find() sulle viste non supportano l’operatore di proiezione $elemMatch.

Il seguente esempio sull’operatore di proiezione $elemMatch presuppone una collezione schools con i seguenti documenti:

{
 _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 questo caso, l’operazione find() cerca tutti i documenti in cui il valore del campo CAP è 63110. La proiezione di $elemMatch restituirebbe solo il primo elemento corrispondente dell’array students in cui il campo school ha un valore pari a 103:

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

Ecco come si presenterebbe il risultato:

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

$slice (proiezione)

L’operatore di proiezione $slice può essere utilizzato per specificare il numero di elementi di un array da restituire nel risultato della query:

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

Può anche essere espresso in questo modo:

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

Per dimostrarlo, potete creare un esempio di raccolta di tweet con i seguenti documenti:

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

La seguente operazione utilizza l’operatore di proiezione $slice sull’array di tweet per restituire l’array con i primi due elementi. Se un array contiene meno di due elementi, vengono restituiti tutti gli elementi dell’array:

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

Questa operazione restituirebbe i seguenti documenti:

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

$ (proiezione)

L’operatore posizionale $ limita il contenuto di un array per restituire il primo elemento che corrisponde alla condizione di interrogazione dell’array. Potete usare $ nel documento di proiezione del metodo find() o del metodo findOne() quando avete bisogno di un solo elemento particolare dell’array nei documenti scelti.

Ecco come si presenta la sintassi dell’operatore $:

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

In questo esempio, la collezione students è composta dai seguenti documenti:

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

Nella seguente query, la proiezione { "grades.$": 1 } restituisce solo il primo elemento maggiore o uguale a 89 per il campo grades:

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

Questa operazione restituisce i seguenti documenti:

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

Operatori di Valutazione

Potete sfruttare gli operatori di valutazione di MongoDB per valutare la struttura complessiva dei dati o i singoli campi di un documento.

Vediamo alcuni comuni operatori di valutazione di MongoDB.

$mod

Questo operatore può essere utilizzato per trovare una corrispondenza tra i documenti in cui il valore di un campo specificato è uguale al resto dopo essere stato diviso per un valore specificato:

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

Supponiamo che abbiate una tabella di auto di diverse marche che possedete nel vostro autosalone. La seguente query vi fornirà tutte le marche di auto i cui numeri di serie sono multipli di 250.

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

$jsonSchema

L’opzione $jsonSchema vi permette di abbinare i documenti che corrispondono allo schema JSON specificato. L’implementazione di MongoDB dello schema JSON include l’aggiunta della parola chiave bsonType, che vi permette di utilizzare tutti i tipi BSON all’interno dell’operatore $jsonSchema.

bsonType può accettare gli stessi alias di stringa che usereste per l’operatore type. Ecco come si presenterebbe la sintassi di $jsonSchema:

{ $jsonSchema: <JSON Schema object> }

In questo caso, l’oggetto JSON schema è formattato in base alla bozza 4 dello standard JSON schema:

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

Ecco un esempio che dimostra il funzionamento di $jsonSchema:

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

Potete anche usare $jsonSchema in un validatore di documenti per applicare lo schema specificato alle operazioni di aggiornamento e inserimento:

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

Tenete presente che ci sono diverse cose che non sono supportate dall’operatore $jsonSchema:

  1. Il tipo intero. Dovete sfruttare il tipo BSON long o int con la parola chiave bsonType.
  2. Parole chiave sconosciute.
  3. Il collegamento delle proprietà e l’ipermedia dello schema JSON, oltre all’uso di riferimenti JSON e puntatori JSON.

$text

L’operatore $text cerca un testo all’interno del contenuto del campo specificato, indicizzato con un indice di testo:

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

In questo caso, il seguente frammento di codice passerà al setaccio la tabella per filtrare tutte le auto che contengono il testo “Porsche”:

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

$regex

L’operatore $regex offre la possibilità di utilizzare le espressioni regolari per effettuare delle corrispondenze con le stringhe nelle query. MongoDB sfrutta le espressioni regolari compatibili con il Perl:

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

L’esempio seguente permette di filtrare tutte le auto in cui è presente la stringa “$78900”:

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

$expr

L’operatore $expr vi permette di sfruttare le espressioni di aggregazione all’interno del linguaggio di query:

{ $expr: { <expression> } }

Potete anche usare $expr per costruire espressioni di query che confrontano i campi dello stesso documento in uno stadio $match. Se lo stadio $match fa parte di uno stadio $lookup, $expr può confrontare i campi con l’aiuto delle variabili let.

$where

Potete sfruttare l’operatore $where per passare al sistema di query una stringa contenente una funzione JavaScript completa o un’espressione JavaScript. L’operatore $where offre una maggiore flessibilità ma richiede che il database elabori la funzione o l’espressione JavaScript per ogni documento della collezione. Potete fare riferimento a questo documento nella funzione o espressione JavaScript usando obj o this.

Ecco un esempio di sintassi:

{ $where: <string|JavaScript Code> }

Ci sono alcune considerazioni chiave da tenere a mente prima di immergerci in un esempio di utilizzo dell’operatore $where:

  • Dovreste utilizzare l’operatore di query $where solo per i documenti di primo livello. L’operatore di query $where non funziona in un documento annidato, come in una query $elemMatch.
  • In generale, dovreste usare $where solo quando non potete esprimere la vostra query con un altro operatore. Se dovete usare $where, assicuratevi di includere almeno un altro operatore di query standard per filtrare l’insieme dei risultati. L’utilizzo di $where richiede una scansione della collezione per una corretta esecuzione.

Ecco un esempio che illustra questo aspetto:

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

Operatori bitwise

Gli operatori bitwise restituiscono i dati in base alle condizioni di posizione dei bit. In parole povere, vengono utilizzati per abbinare valori numerici o binari in cui qualsiasi bit di un insieme di posizioni di bit ha un valore di 1 o 0.

$bitsAllSet

Questo operatore corrisponde a tutti i documenti in cui tutte le posizioni di bit fornite dalla query sono impostate (cioè 1) nel campo:

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

Il valore del campo deve essere un’istanza di BinData o un numero per $bitsAllSet per corrispondere al documento corrente.

Nella seguente istanza, stiamo sfruttando una raccolta con i seguenti documenti:

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

La query riportata di seguito utilizzerà l’operatore $bitsAllSet per verificare se il campo a ha dei bit impostati in posizione 1 e in posizione 5, dove il bit meno significativo si trova in posizione 0:

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

Questa query corrisponde ai seguenti documenti:

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

$bitsAllClear

L’operatore $bitsAllClear corrisponderà ai documenti in cui tutte le posizioni dei bit fornite dalla query sono chiare o 0:

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

Useremo l’esempio di $bitsAllSet per dimostrare l’uso di $bitsAllClear. La seguente query utilizzerebbe questo operatore per verificare se il campo a ha i bit liberi nelle posizioni 1 e 5:

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

Questa query corrisponderebbe ai seguenti documenti:

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

Meta-operatori

Esistono diversi modificatori di query che vi permettono di modificare il comportamento o l’output di una query in MongoDB. Le interfacce dei driver possono fornire metodi di cursore che li avvolgono per il vostro utilizzo.

$hint

MongoDB ha deprecato $hint dalla v3.2. Tuttavia, questo operatore potrebbe essere ancora disponibile per i driver MongoDB come Go, Java, Scala, Ruby, Swift, ecc. Può forzare l’ottimizzatore di query a sfruttare un indice specifico per soddisfare la query, che può essere menzionata sia per documento che per nome dell’indice.

Potete anche usare l’operatore $hint per testare le strategie di indicizzazione e le prestazioni delle query. Per esempio, prendiamo la seguente operazione:

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

Questa operazione restituirebbe tutti i documenti della collezione users sfruttando l’indice sul campo age.

Potete anche indicare un suggerimento utilizzando una delle seguenti forme:

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

Se esiste un filtro indice per la forma della query, MongoDB ignorerà semplicemente il campo $hint.

$comment

L’operatore $comment vi permette di aggiungere un commento a una query in qualsiasi $query contesto possa apparire. Poiché i commenti si propagano al log del profilo, l’aggiunta di un commento può rendere più facile l’interpretazione e la tracciabilità del vostro profilo.

Potete utilizzare $comment in uno dei tre modi seguenti:

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

Se volete aggiungere commenti alle espressioni delle query in altri contesti, come nel caso di db.collection.update(), usate l’operatore di query $comment invece del meta-operatore.

$max

Potete citare un valore di $max per specificare il limite superiore esclusivo di un particolare indice per limitare i risultati di find(). Questo operatore specificherà il limite superiore per tutte le chiavi di un ordine specifico nell’indice.

Mongosh fornisce il seguente metodo wrapper max():

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

Potete anche citare $max con le due forme seguenti:

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

Per esempio, se volete specificare il limite superiore esclusivo, tenete presente le seguenti operazioni su una collezione chiamata collezione che contiene un indice { age: 1 }:

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

Questa operazione limita la query ai documenti in cui l’età del campo è inferiore a 100 e forza un piano di query che scansiona l’indice { age: 1 } da minKey a 100.

$explain

Questo operatore fornisce informazioni sul piano di query. Restituisce un documento che descrive gli indici e i processi utilizzati per eseguire la query. Questo può essere utile quando si cerca di ottimizzare una query.

Potete citare l’operatore $explain in una delle seguenti forme:

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

Migliori Pratiche per gli Operatori di MongoDB

In questa sezione vedremo alcune delle migliori pratiche per l’utilizzo di questi operatori MongoDB.

Incorporare e Referenziare

L’incorporamento è un’estensione naturale della modellazione dei dati. Permette di evitare i join delle applicazioni, riducendo così gli aggiornamenti e le query.

Potete incorporare i dati con una relazione 1:1 all’interno di un singolo documento. Tuttavia, anche i dati con una relazione molti:1 in cui “molti” oggetti appaiono con i loro documenti genitori possono essere dei buoni candidati.

Memorizzare questi tipi di dati nello stesso documento sembra una scelta prudente. Tuttavia, l’incorporamento offre prestazioni migliori per le operazioni di lettura con questo tipo di localizzazione dei dati.

I modelli di dati incorporati possono anche aiutare gli sviluppatori ad aggiornare i dati associati con un’unica operazione di scrittura. Questo funziona perché le scritture di un singolo documento sono transazionali.

Dovreste prendere in considerazione l’utilizzo del referenziamento per i seguenti scenari:

  • Quando si aggiorna un segmento del documento e questo continua ad allungarsi, mentre il resto del documento è statico.
  • Quando un documento viene consultato ma contiene dati che vengono utilizzati raramente. L’inclusione aumenterebbe solo i requisiti di memoria, quindi il riferimento ha più senso.
  • Quando le dimensioni del documento superano il limite di 16 MB di MongoDB. Questo può accadere quando si modellano relazioni molti:1 (per esempio, dipendenti:reparto).

Esaminare i Modelli di Profilazione e di Query

Per la maggior parte degli sviluppatori, il primo passo per ottimizzare le prestazioni è capire i modelli di query attuali e previsti. Una volta che conoscete abbastanza bene i modelli di query della vostra applicazione, potete creare il vostro modello di dati e scegliere gli indici appropriati.

Le sviluppatrici e gli sviluppatori di MongoDB hanno accesso a diversi strumenti potenti che permettono loro di migliorare le prestazioni. Ma questo non significa che i profili e i modelli di query possano essere ignorati.

Per esempio, un modo semplice per aumentare le prestazioni è analizzare i modelli di query e capire dove è possibile inserire i dati. Altri modi per migliorare le prestazioni di MongoDB dopo aver identificato i principali modelli di query sono:

  • Assicurarsi di avere degli indici su tutti i campi su cui si effettuano le query.
  • Memorizzare i risultati delle sotto-query frequenti sui documenti per ridurre il carico di lettura.
  • Dare un’occhiata ai log per individuare le query lente e poi controllare gli indici.

Rivedere l’Indicizzazione e la Modellazione dei Dati

Durante la creazione del modello dei dati, dovrete decidere come modellare le relazioni tra i dati. Scegliere quando incorporare un documento piuttosto che creare un riferimento a documenti separati in raccolte diverse, per esempio, è un esempio di considerazione specifica per l’applicazione.

Un grande vantaggio dei documenti JSON è che permettono agli sviluppatori di modellare i dati in base ai requisiti dell’applicazione. L’annidamento di sottodocumenti e array vi aiuta a modellare relazioni complesse tra i dati sfruttando semplici documenti di testo.

Potete usare MongoDB anche per modellare quanto segue:

  • Dati geospaziali
  • Strutture tabellari, piatte e colonnari
  • Semplici coppie chiave-valore
  • Dati di serie temporali
  • Angoli e nodi di strutture di dati a grafo connesso e simili

Monitorare lo Sharding e la Replica

La replica può essere fondamentale per migliorare le prestazioni in quanto aumenta la disponibilità dei dati grazie alla scalabilità orizzontale. La replica può portare a prestazioni migliori e a una maggiore sicurezza grazie alla ridondanza.

Il monitoraggio delle prestazioni può essere una seccatura che richiede risorse e tempo aggiuntivi per garantire un funzionamento regolare. Potete sfruttare gli strumenti di monitoraggio delle prestazioni disponibili sul mercato che rispondono alle vostre esigenze specifiche.

Per esempio, Kinsta APM è in grado di raccogliere informazioni con data e ora sulle query del database MySQL del vostro sito WordPress, sui processi PHP, sulle chiamate HTTP esterne e molto altro ancora. Potete anche usare questo strumento gratuito per eseguire il debug:

  • Chiamate API lunghe
  • Lunghe richieste di URL esterni
  • Query di database lente, per citarne alcune.

In MongoDB, la replica può essere realizzata attraverso set di replica che consentono agli sviluppatori di copiare i dati da un nodo o server primario su più secondari. In questo modo la replica consente di eseguire alcune query sui secondari anziché sul primario, evitando la contesa e migliorando il bilanciamento del carico.

I cluster sharded di MongoDB sono un altro modo per migliorare potenzialmente le prestazioni. Come la replica, lo sharding può essere utilizzato per distribuire grandi insiemi di dati su più server.

Sfruttando una chiave shard, gli sviluppatori possono copiare shard o pezzi di dati su più server. Questi server possono lavorare insieme per utilizzare tutti i dati.

Lo sharding presenta una serie di vantaggi, tra cui la scalabilità orizzontale per le scritture/letture, una maggiore disponibilità e una maggiore capacità di archiviazione.

Determinare l’Uso della Memoria

MongoDB dà il meglio di sé quando l’insieme di lavoro di un’applicazione (cioè i dati e gli indici a cui si accede di frequente) entra in memoria senza problemi. Anche se altri fattori sono fondamentali per le prestazioni, la dimensione della RAM è la più importante per il dimensionamento dell’istanza.

Quando l’insieme di lavoro di un’applicazione è contenuto nella RAM, l’attività di lettura dal disco deve essere bassa. Ma se l’insieme di lavoro supera la RAM del server o le dimensioni dell’istanza, l’attività di lettura inizierà ad aumentare.

Se vedete che questo accade, potreste risolvere il problema passando a un’istanza più grande con più memoria.

Posizionare i Campi a Valore Multiplo alla Fine

Se state indicizzando un paio di campi e uno dei campi che volete interrogare utilizza uno di quegli operatori “multi-valore”, allora dovreste metterli alla fine dell’indice. Dovete ordinare l’indice in modo che i campi interrogati per i valori esatti vengano prima e gli operatori “multivalore” vengano visualizzati per ultimi nell’indice.

Un’eccezione è rappresentata dall’ordinamento in base ai campi. Posizionate questi ultimi tra i campi “multi-valore” e i campi esatti per ridurre la quantità di ordinamenti in memoria necessari.

Riepilogo

Per MongoDB, la velocità è tutto. Per restituire rapidamente le query, MongoDB sfrutta gli operatori per eseguire operazioni matematiche o logiche. In poche parole, capire gli operatori di MongoDB è la chiave per padroneggiare MongoDB.

In questo articolo abbiamo evidenziato alcuni degli operatori chiave di MongoDB che potete utilizzare sui vostri dati, come gli operatori di confronto, gli operatori logici, i meta-operatori e gli operatori di proiezione, per citarne alcuni. Inoltre, vi aiuta a capire come utilizzare gli operatori di MongoDB e le migliori pratiche che vi permetteranno di sfruttarli al meglio.

Tra tutti gli operatori, quale/i usate più spesso e perché? Ditecelo nei commenti qui sotto: ci piacerebbe conoscere le vostre opinioni!

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.