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.