V tomto tutoriálu budeme používat official dummy dataset
, která obsahuje četné dokumenty o restauracích z celé oblasti New Yorku.
Zde je příklad základní struktury dokumentu v této kolekci pomocí .findOne()
metoda:
> 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"
}
Síla hledání
Nejdůležitějším kouskem skládačky při vyhledávání v kolekci MongoDB je jednoduchý, ale flexibilní db.collection.find()
metoda.
Pomocí .find()
, můžete se snadno dotazovat na kolekci dokumentů předáním několika jednoduchých parametrů a vrátit cursor
. cursor
je prostě sada výsledků a lze ji iterovat za účelem manipulace nebo jiného využití dokumentů, na které ukazuje cursor
.
Jako jednoduchý příklad .find()
metoda v akci, pokusíme se najít všechny restaurace v naší kolekci, které server Hamburgers
jako jejich 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" }
...
Sada výsledků je poměrně velká, takže lepším měřením pro naše testovací příklady by bylo řetězení .count()
metoda na .find()
abyste jednoduše viděli, kolik dokumentů odpovídalo našemu dotazu:
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
To je spousta hamburgerů!
Hledání podobností slov pomocí regulárního výrazu
Nyní, když používáme .find()
k dotazu na naši sbírku můžeme skutečně nepatrně upravit svou syntaxi a začít hledat shody na základě slova nebo fráze, které mohou být částečné shodu v daném poli, podobně jako LIKE
operátor pro SQL motory.
Trik je v použití regular expressions
(nebo regex
zkráceně), což je v podstatě textový řetězec, který definuje vzor vyhledávání. Existuje několik regular expressions
enginy, které jsou napsány v mírně odlišné syntaxi, ale základy jsou v zásadě stejné, a v tomto případě MongoDB používá Perl Regex (PCRE)
motor.
Na nejzákladnější úrovni regex
výraz je řetězec (řada znaků) uzavřený na obou stranách jedním lomítkem (/
).
Například pokud chceme použít regex
provést stejný dotaz jako výše a zjistit, kolik restaurací podává Hamburgers
, můžeme nahradit náš řetězec "Hamburgers"
pomocí /Hamburgers/
místo toho:
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Zapálení pozorovatelé mohou rozpoznat, že jsme na skutečném dotazu, který provádíme, prakticky nic nezměnili – stále jednoduše vyhledáváme všechny dokumenty, kde je cuisine
pole se rovná řetězec "Hamburgers"
.
To znamená jednoduše pomocí regex
místo normálního „řetězce v uvozovkách“ můžeme začít hledat částečné shody slov/frází místo toho.
Podívejme se například na borough
pole, abyste získali lepší představu o tom, jak to funguje. Nejprve si všimneme, že v naší kolekci je celkem šest městských částí:
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Nyní použijeme regex
zjistit, kolik restaurací je v Bronx
čtvrť:
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Ale představte si, že chceme najít počet restaurací, kde je borough
začíná na první tři znaky "Bro"
. Upravili bychom náš regex
velmi mírně, asi takto:
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
V této sadě výsledků vidíme více než 6 000 dalších dokumentů, což dává smysl, protože nejenže dostáváme výsledky tam, kde borough
je "Bronx"
, ale také vše pro "Brooklyn"
také.
Znak stříšky (^
) určuje umístění v našem řetězci, které by mělo být začátkem , takže pokud bychom měli dokument, kde by tato tři písmena byla uprostřed pole, nedostali bychom shodu.
Jako další rychlý příklad, pojďme hledat kdekoli v poli pro znaky "at"
, což by nám mělo poskytnout výsledky pro oba "Manhattan"
a "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
Náš poslední dotaz samozřejmě spojil tyto dvě sady výsledků do jedné.
Můžete si všimnout, že i když naše znaky "AT"
jsou v našem regex
velká písmena řetězec, ale jsou malá ve skutečných záznamech dokumentů jsme stále vraceli výsledky. Je to proto, že jsme přidali také speciální i
příznak za naším uzavíracím lomítkem regulárního výrazu (/
). To informuje regex
vyhledávač, u kterého chceme, aby vyhledávání case insensitive
, odpovídající bez ohledu na velká nebo malá písmena.