Til denne øvelse bruger vi det official dummy dataset
, som indeholder talrige restaurantdokumenter fra hele New York-området.
Her er et eksempel på den grundlæggende dokumentstruktur i denne samling ved hjælp af .findOne()
metode:
> 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"
}
Kraften ved at finde
Den vigtigste brik i puslespillet, når du søger i en MongoDB-samling, er den enkle, men fleksible db.collection.find()
metode.
Med .find()
, kan du nemt forespørge en samling af dokumenter ved at sende nogle få simple parametre og returnere en cursor
. En cursor
er simpelthen et resultatsæt og kan gentages for at manipulere eller på anden måde gøre brug af de dokumenter, der peges på af cursor
.
Som et simpelt eksempel på .find()
metode i aktion, vil vi forsøge at finde alle restauranter i vores samling, der serverer Hamburgers
som deres 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" }
...
Resultatsættet er ret stort, så en bedre måling for vores testeksempler ville være at sammenkæde .count()
metode til .find()
for blot at se, hvor mange dokumenter der matchede vores forespørgsel:
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
Det er mange burgere!
Søgning efter ord-ligheder ved hjælp af regulært udtryk
Nu hvor vi bruger .find()
for at forespørge på vores samling kan vi faktisk ændre vores syntaks en smule og begynde at søge efter match baseret på et ord eller en sætning, der kan være en delvis match inden for et givet felt, svarende til LIKE
operatør til SQL-motorer.
Tricket er at bruge regular expressions
(eller regex
for kort), som dybest set er en tekststreng, der definerer et søgemønster. Der er en række regex
motorer, der er skrevet i lidt forskellig syntaks, men de grundlæggende principper er alle grundlæggende de samme, og i dette tilfælde bruger MongoDB Perl Regex (PCRE)
motor.
På det mest grundlæggende niveau, et regex
udtryk er en streng (serie af tegn) omgivet på begge sider af en enkelt skråstreg (/
).
For eksempel, hvis vi vil bruge regex
for at udføre den samme forespørgsel som ovenfor og finde ud af, hvor mange restauranter der serverer Hamburgers
, kan vi erstatte vores streng "Hamburgers"
med /Hamburgers/
i stedet:
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Spændte iagttagere vil måske erkende, at vi i virkeligheden ikke har ændret noget ved den faktiske forespørgsel, vi udfører – vi søger stadig blot alle dokumenter, hvor cuisine
felt er lig med strengen "Hamburgers"
.
Når det er sagt, ved blot at bruge regex
i stedet for en normal "anført streng", kan vi begynde at lede efter delvise ord/sætningsmatches i stedet.
Lad os for eksempel se på borough
felt for at få en bedre ide om, hvordan dette fungerer. Først vil vi bemærke, at der er seks bydele i alt inden for vores samling:
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Lad os nu bruge regex
for at finde ud af, hvor mange restauranter der er i Bronx
bydel:
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Men forestil dig, at vi ønsker at finde antallet af restauranter, hvor borough
starter med de første tre tegn "Bro"
. Vi ville ændre vores regex
meget lidt, sådan:
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
Vi ser over 6000 yderligere dokumenter i dette resultatsæt, hvilket giver mening, fordi vi ikke kun får resultater, hvor borough
er er "Bronx"
, men også alt til "Brooklyn"
også.
Caret-tegnet (^
) angiver placeringen i vores streng, som skal være begyndelsen , så hvis vi havde et dokument, hvor de tre bogstaver var i midten af feltet, ville vi ikke få et match.
Som et andet hurtigt eksempel, lad os søge hvor som helst i feltet for tegnene "at"
, hvilket skulle give os resultater for både "Manhattan"
og "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
Sikkert nok har vores sidste forespørgsel kombineret de to resultatsæt til ét.
Du bemærker måske, at selvom vores tegn "AT"
er store bogstaver i vores regex
streng, men de er små bogstaver i de faktiske dokumentposter returnerede vi stadig resultater. Dette skyldes, at vi også tilføjede den særlige i
flag efter vores regex afsluttende skråstreg (/
). Dette informerer regex
motor, som vi ønsker, at søgningen skal være case insensitive
, matchende uanset store eller små bogstaver.