Per questo tutorial utilizzeremo il official dummy dataset
, che contiene numerosi documenti di ristoranti provenienti da tutta l'area di New York.
Ecco un esempio della struttura di base del documento in questa raccolta, utilizzando .findOne()
metodo:
> db.restaurants.findOne()
{
"_id" : ObjectId("56c651e7d84ccfde319961af"),
"address" : {
"building" : "469",
"coord" : [
-73.961704,
40.662942
],
"street" : "Flatbush Avenue",
"zipcode" : "11225"
},
"borough" : "Brooklyn",
"cuisine" : "Hamburgers",
"grades" : [
{
"date" : ISODate("2014-12-30T00:00:00Z"),
"grade" : "A",
"score" : 8
},
{
"date" : ISODate("2014-07-01T00:00:00Z"),
"grade" : "B",
"score" : 23
},
{
"date" : ISODate("2013-04-30T00:00:00Z"),
"grade" : "A",
"score" : 12
},
{
"date" : ISODate("2012-05-08T00:00:00Z"),
"grade" : "A",
"score" : 12
}
],
"name" : "Wendy'S",
"restaurant_id" : "30112340"
}
Il potere di trovare
Il pezzo più importante del puzzle durante la ricerca all'interno di una raccolta MongoDB è il semplice ma flessibile db.collection.find()
metodo.
Con .find()
, puoi facilmente interrogare una raccolta di documenti, passando alcuni semplici parametri, e restituire un cursor
. Un cursor
è semplicemente un set di risultati e può essere ripetuto per manipolare o altrimenti utilizzare i documenti a cui punta il cursor
.
Come semplice esempio di .find()
metodo in azione, cercheremo di trovare tutti i ristoranti nella nostra raccolta che server Hamburgers
come loro cuisine
:
>db.restaurants.find( { cuisine: "Hamburgers" } )
{ "_id" : ObjectId("56c651e7d84ccfde319961af"), "address" : { "building" : "469", "coord" : [ -73.961704, 40.662942 ], "street" : "Flatbush Avenue", "zipcode" : "11225" }, "borough" : "Brooklyn", "cuisine" : "Hamburgers", "grades" : [ { "date" : ISODate("2014-12-30T00:00:00Z"), "grade" : "A", "score" : 8 }, { "date" : ISODate("2014-07-01T00:00:00Z"), "grade" : "B", "score" : 23 }, { "date" : ISODate("2013-04-30T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2012-05-08T00:00:00Z"), "grade" : "A", "score" : 12 } ], "name" : "Wendy'S", "restaurant_id" : "30112340" }
...
Il set di risultati è piuttosto ampio, quindi una misurazione migliore per i nostri esempi di test sarebbe quella di concatenare .count()
metodo su .find()
per vedere semplicemente quanti documenti hanno soddisfatto la nostra richiesta:
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
Sono un sacco di hamburger!
Ricerca di somiglianze di parole usando Regex
Ora che stiamo usando .find()
per interrogare la nostra raccolta, possiamo effettivamente modificare leggermente la nostra sintassi e iniziare a cercare corrispondenze in base a una parola o frase che potrebbe essere un parziale corrispondenza all'interno di un determinato campo, simile a LIKE
operatore per motori SQL.
Il trucco è utilizzare regular expressions
(o regex
in breve), che è fondamentalmente una stringa di testo che definisce un modello di ricerca. Ci sono un certo numero di regex
motori scritti con una sintassi leggermente diversa, ma i fondamenti sono sostanzialmente tutti gli stessi e, in questo caso, MongoDB utilizza Perl Regex (PCRE)
motore.
Al livello più elementare, una regex
espressione è una stringa (serie di caratteri) racchiusa su entrambi i lati da una singola barra (/
).
Ad esempio, se vogliamo usare regex
per eseguire la stessa query di cui sopra e scoprire quanti ristoranti servono Hamburgers
, possiamo sostituire la nostra stringa "Hamburgers"
con /Hamburgers/
invece:
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Osservatori attenti potrebbero riconoscere che non abbiamo effettivamente cambiato nulla riguardo alla query effettiva che stiamo eseguendo:stiamo ancora semplicemente cercando tutti i documenti in cui la cuisine
il campo è uguale a la stringa "Hamburgers"
.
Detto questo, semplicemente usando regex
invece di una normale "stringa tra virgolette", possiamo iniziare a cercare corrispondenze parziali di parole/frasi invece.
Ad esempio, diamo un'occhiata al borough
campo per avere un'idea migliore di come funziona. Per prima cosa noteremo che ci sono sei distretti in totale nella nostra collezione:
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Ora usiamo regex
per scoprire quanti ristoranti ci sono nel Bronx
borgo:
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Ma immagina di voler trovare il numero di ristoranti in cui borough
inizia con i primi tre caratteri "Bro"
. Modificheremmo la nostra regex
molto leggermente, così:
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
Stiamo vedendo oltre 6000 documenti aggiuntivi in questo set di risultati, il che ha senso perché non solo stiamo ottenendo risultati dove il borough
è "Bronx"
, ma anche tutto per "Brooklyn"
anche.
Il carattere di accento circonflesso (^
) specifica la posizione nella nostra stringa che dovrebbe essere l'inizio , quindi se avessimo un documento in cui quelle tre lettere fossero al centro del campo, non avremmo una corrispondenza.
Come altro rapido esempio, cerchiamo ovunque nel campo per i caratteri "at"
, che dovrebbe darci risultati per entrambi "Manhattan"
e "Staten Island"
:
> db.restaurants.find( { borough: /Manhattan/ } ).count()
10259
> db.restaurants.find( { borough: /Staten Island/ } ).count()
969
> db.restaurants.find( { borough: /AT/i } ).count()
11228
Abbastanza sicuro, la nostra query finale ha combinato i due set di risultati in uno.
Potresti notare che anche se i nostri caratteri "AT"
sono maiuscole nella nostra regex
stringa, ma sono minuscole nei record del documento effettivo, abbiamo comunque restituito i risultati. Questo perché abbiamo anche aggiunto lo speciale i
flag dopo la nostra barra di chiusura regex (/
). Questo informa la regex
motore che vogliamo che la ricerca sia case insensitive
, corrispondenti indipendentemente dal maiuscolo o dal minuscolo.