За този урок ще използваме official dummy dataset , който съдържа множество документи за ресторанти от района на Ню Йорк.
Ето пример за основната структура на документа в тази колекция, използвайки .findOne() метод:
> 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"
}
Силата на намирането
Най-важната част от пъзела при търсене в колекция MongoDB е простият, но гъвкав db.collection.find() метод.
С .find() , можете лесно да заявите колекция от документи, като подадете няколко прости параметъра и върнете cursor . cursor е просто набор от резултати и може да бъде повторен, за да манипулира или по друг начин да използва документите, към които се сочи от cursor .
Като прост пример за .find() метод в действие, ще се опитаме да намерим всички ресторанти в нашата колекция, които сървърът на Hamburgers като тяхната 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" }
...
Резултатът е доста голям, така че по-добро измерване за нашите тестови примери би било да се свърже .count() метод върху .find() за да видите просто колко документа отговарят на нашата заявка:
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
Това са много бургери!
Търсене на прилики на думи с помощта на Regex
Сега, когато използваме .find() за да потърсим нашата колекция, всъщност можем да модифицираме нашия синтаксис много леко и да започнем да търсим съвпадения въз основа на дума или фраза, която може да е частична съвпадение в дадено поле, подобно на LIKE оператор за SQL машини.
Номерът е да се използват regular expressions (или regex накратко), което е основно текстов низ, който дефинира модел за търсене. Има няколко regex двигатели, които са написани в малко по-различен синтаксис, но основите са по същество еднакви и в този случай MongoDB използва Perl Regex (PCRE) двигател.
На най-основното ниво, regex изразът е низ (поредица от знаци), затворен от двете страни с една наклонена черта (/ ).
Например, ако искаме да използваме regex за да извършите същата заявка като по-горе и да разберете колко ресторанта сервират Hamburgers , можем да заменим нашия низ "Hamburgers" с /Hamburgers/ вместо това:
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Запалените наблюдатели може да разберат, че на практика не сме променили нищо относно действителната заявка, която изпълняваме – ние все още просто търсим всички документи, където cuisine поле еравно на низът "Hamburgers" .
Това каза, просто като използвате regex вместо нормален „низ в кавички“, можем да започнем да търсим частични съвпадения на дума/фраза вместо това.
Например, нека разгледаме borough поле, за да добиете по-добра представа как работи това. Първо ще забележим, че в нашата колекция има общо шест района:
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Сега нека използваме regex за да разберете колко ресторанта има в Bronx квартал:
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Но представете си, че искаме да намерим броя на ресторантите, където borough започва с първите три знака "Bro" . Бихме променили нашия regex съвсем леко, така:
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
Виждаме над 6000 допълнителни документа в този набор от резултати, което има смисъл, защото не само получаваме резултати там, където borough е "Bronx" , но и всичко за "Brooklyn" също.
Знакът на карета (^ ) определя местоположението в нашия низ, което трябва да е началото , така че ако имахме документ, в който тези три букви бяха в средата на полето, нямаше да получим съвпадение.
Като друг бърз пример, нека търсим навсякъде в полето за знаците "at" , което трябва да ни даде резултати и за двата "Manhattan" и "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
Разбира се, нашата последна заявка е комбинирала двата резултата в един.
Може да забележите, че въпреки че нашите знаци "AT" са с главни букви в нашия regex низ, но те са с малки букви в действителните записи на документи, ние все още връщахме резултати. Това е така, защото добавихме и специалния i флаг след затварящата наклонена черта на нашия редовен израз (/ ). Това информира regex машина, която искаме търсенето да е case insensitive , съвпадащи независимо от главни или малки букви.