Voor deze tutorial gebruiken we de official dummy dataset
, die tal van restaurantdocumenten bevat uit de omgeving van New York.
Hier is een voorbeeld van de basisdocumentstructuur in deze verzameling, met behulp van de .findOne()
methode:
> 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"
}
De kracht van vinden
Het belangrijkste puzzelstukje bij het zoeken binnen een MongoDB-verzameling is de eenvoudige maar flexibele db.collection.find()
methode.
Met .find()
, kunt u eenvoudig een verzameling documenten opvragen door een paar eenvoudige parameters door te geven en een cursor
terug te sturen . Een cursor
is gewoon een resultaatset en kan worden herhaald om de documenten te manipuleren of anderszins te gebruiken waarnaar wordt verwezen door de cursor
.
Als een eenvoudig voorbeeld van de .find()
methode in actie, we zullen proberen alle restaurants in onze collectie te vinden die server Hamburgers
als hun 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" }
...
De resultatenset is vrij groot, dus een betere maatstaf voor onze testvoorbeelden zou zijn om de .count()
te koppelen methode naar .find()
om eenvoudig te zien hoeveel documenten overeenkwamen met onze zoekopdracht:
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
Dat zijn veel hamburgers!
Zoeken naar woordovereenkomsten met Regex
Nu we .find()
gebruiken om onze verzameling te doorzoeken, kunnen we onze syntaxis zelfs maar een klein beetje aanpassen en beginnen met zoeken naar overeenkomsten op basis van een woord of zin die een gedeeltelijk kan zijn match binnen een bepaald veld, vergelijkbaar met de LIKE
operator voor SQL-engines.
De truc is om regular expressions
te gebruiken (of regex
in het kort), wat in feite een tekenreeks is die een zoekpatroon definieert. Er zijn een aantal regex
engines die in een iets andere syntaxis zijn geschreven, maar de grondbeginselen zijn in principe allemaal hetzelfde, en in dit geval gebruikt MongoDB de Perl Regex (PCRE)
motor.
Op het meest basale niveau, een regex
uitdrukking is een tekenreeks (reeks tekens) die aan beide zijden is ingesloten door een enkele schuine streep (/
).
Als we bijvoorbeeld regex
. willen gebruiken om dezelfde zoekopdracht als hierboven uit te voeren en erachter te komen hoeveel restaurants Hamburgers
serveren , kunnen we onze string "Hamburgers"
vervangen met /Hamburgers/
in plaats daarvan:
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Scherpe waarnemers zullen misschien herkennen dat we feitelijk niets hebben veranderd aan de eigenlijke zoekopdracht die we uitvoeren - we zoeken nog steeds gewoon alle documenten op waar de cuisine
veld is gelijk aan de string "Hamburgers"
.
Dat gezegd hebbende, door simpelweg regex
. te gebruiken in plaats van een normale "tekenreeks tussen aanhalingstekens", kunnen we beginnen te zoeken naar gedeeltelijke woord/zin-overeenkomsten in plaats daarvan.
Laten we bijvoorbeeld eens kijken naar de borough
veld om een beter idee te krijgen van hoe dit werkt. Eerst zullen we zien dat er in totaal zes stadsdelen in onze collectie zijn:
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Laten we nu regex
gebruiken om erachter te komen hoeveel restaurants er in de Bronx
zijn gemeente:
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Maar stel je voor dat we het aantal restaurants willen vinden waar borough
begint met de eerste drie tekens "Bro"
. We zouden onze regex
. aanpassen heel lichtjes, zoals zo:
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
We zien meer dan 6000 extra documenten in deze resultatenset, wat logisch is omdat we niet alleen resultaten krijgen waar de borough
is "Bronx"
, maar ook alles voor "Brooklyn"
ook.
Het caret-teken (^
) specificeert de locatie in onze string die het begin . zou moeten zijn , dus als we een document hadden waarin die drie letters in het midden van het veld stonden, zouden we geen overeenkomst krijgen.
Laten we als een ander snel voorbeeld overal zoeken in het veld voor de karakters "at"
, wat ons resultaten zou moeten geven voor zowel "Manhattan"
en "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
En ja hoor, onze laatste zoekopdracht heeft de twee resultatensets gecombineerd tot één resultaat.
Je merkt misschien dat, hoewel onze karakters "AT"
zijn hoofdletters in onze regex
tekenreeks, maar ze zijn kleine letters in de eigenlijke documentrecords hebben we nog steeds resultaten geretourneerd. Dit komt omdat we ook de speciale i
. hebben toegevoegd vlag na onze regex afsluitende slash (/
). Dit informeert de regex
engine waarvan we willen dat de zoekopdracht case insensitive
is , overeenkomend ongeacht hoofdletters of kleine letters.