MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Come utilizzare un'istruzione SQL LIKE in MongoDB

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.