MongoDB学习笔记三:查询
MongoDB中使用find來進(jìn)行查詢。查詢就是返回一個(gè)集合中文檔的子集,子集合的范圍從0個(gè)文檔到整個(gè)集合。find的第一個(gè)參數(shù)決定了要返回哪些文檔,其形式也是一個(gè)文檔,說明要執(zhí)行的查詢細(xì)節(jié)。
空的查詢文檔{}會匹配集合的全部內(nèi)容。要是不指定查詢文檔,默認(rèn)就是{}。
例如:
> db.c.find()
將返回集合c中的所有內(nèi)容。
查找所有"age"的值為27的文檔:
> db.users.find({"age" : 27})
查找所有值為"joe"的"username"鍵:
> db.users.find({"username" : "joe"})
可以通過向查詢文檔加入多個(gè)鍵/值對的方式來將多個(gè)查詢條件組合在一起。例如,查詢所有用戶名為"joe"且年齡為27歲的用戶:
> db.users.find({"username" : "joe", "age" : 27})
『指定返回的鍵』
有時(shí)并不需要將文檔中的所有鍵/值對都返回。遇到這種情況,可以通過find(或者findOne)的第二個(gè)參數(shù)來指定想要的鍵。
例如,如果只對用戶集合的"username"和"email"鍵感興趣,可以使用如下查詢返回這些鍵:
> db.users.find({}, {"username" : 1, "email" : 1})
也可以用第二個(gè)參數(shù)來剔除查詢結(jié)果中的某個(gè)鍵/值對。例如,文檔中有很多鍵,但是不希望結(jié)果中含有"fatal_weakness"鍵:
> db.users.find({}, {"fatal_weakness" : 0})
也可以用來防止返回"_id":
> db.users.find({}, {"username" : 1, "_id" : 0})
查詢條件
比較操作符"$lt"、"$lte"、"$gt"、"$gte"分別對應(yīng)<、<=、>、>=。
例:查詢在18~30歲(含)的用戶:
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
查詢在2007年1月1日前注冊的人:
> start = new Date("01/01/2007")
> db.users.find({"registered" : {"$lt" : start}})
使用條件操作符"$ne"表示"不相等"。
例:查詢所有名字不為"joe"的用戶:
> db.users.find({"username" : {"$ne" : "joe"}})
"$ne"能用于所有類型的數(shù)據(jù)。
『OR查詢』
MongoDB中有兩種方式進(jìn)行OR查詢:"$in"用來查詢一個(gè)鍵的多個(gè)值;"$or"用來完成多個(gè)鍵值的任意給定值。
對于單一鍵要是有多個(gè)值與其匹配的話,就要用"$in"加一個(gè)條件數(shù)組。例如,抽獎(jiǎng)活動(dòng)的中獎(jiǎng)號碼是725、542和390.要找出全部這些中獎(jiǎng)數(shù)據(jù),可以構(gòu)建如下查詢:
> db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})
"$in"可以指定不同的類型的條件和值。例如,在逐步將用戶名的ID號遷移成用戶名的過程中,要做兼顧二者的查詢:
> db.users.find({"user_id" : {"$in" : [12345, "joe"]}})
這會匹配"user_id"等于12345的文檔,也會匹配"user_id"等于"joe"的文檔。
如果"$in"對應(yīng)的數(shù)組只有一個(gè)值,那么和直接匹配這個(gè)值效果是一樣的。例如,{ticket_no : {$in : [725]}}等價(jià)于{ticket_no : {$in : 725}}。
與"$in"相對的是"$nin",將返回與數(shù)組中所有條件都不匹配的文檔。要是想返回所有沒有中獎(jiǎng)的人,就可以用如下方法進(jìn)行查詢:
> db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}})
查詢將會返回沒有那些號碼的人。
"$or"接受一個(gè)包含所有可能條件的數(shù)組作為參數(shù)。例:找"ticket_no"為725或者"winner"為true的文檔:
> db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]})
"$or"可以含有其他條件句。例如,如果想要將"ticket_no"與那三個(gè)值匹配上,外加"winner"鍵,就可以這么做:
> db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}}, {"winner" : true}]})
『$not』
"$not"是元條件句,即可以用在任何其他條件之上。例:對于取模運(yùn)算符"$mod"來說。"$mod"會將查詢得知除以第一個(gè)給定值,若余數(shù)等于第二個(gè)給定值則返回該結(jié)果:
> db.users.find({"id_num" : {"$mod" : [5, 1]}})
上面的結(jié)果會返回"id_num"值為1、6/11/16等的用戶。如果要返回"id_num"為2、3、4、5、7、8、9、10、12等的用戶,則應(yīng)使用"$not":
> db.users.find("id_num" : {"$not" : {"$mod" : [5, 1]}})
!"$not"與正則表達(dá)式聯(lián)合使用的時(shí)候極為有用,用來查找那些與特定模式不符的文檔。
『條件句的規(guī)則』
條件句是內(nèi)層文檔的鍵,而修改器則是外層文檔的鍵。
一個(gè)鍵可以由多個(gè)條件,但是一個(gè)鍵不能對應(yīng)多個(gè)更新修改器。
『特定于類型的查詢』
"null"不僅能匹配自身,而且能匹配"不存在的"。
如果僅僅想要匹配鍵值為null的文檔,既要檢查該鍵的值是否為null,還要通過"$exists"條件判定值已經(jīng)已存在:
> db.c.find({"z" : {"$in" : [null], "$exists" : true}})
『正則表達(dá)式』
例:想要查找所有名為Joe或者joe的用戶,就可以使用正則表達(dá)式執(zhí)行忽略大小寫的匹配:
> db.users.find({"name" : /joe/i})
匹配各種大小寫的joe以及joey:
> db.users.find({"name" : /joe?/i})
MongoDB使用Perl兼容的正則表達(dá)式(PCRE)庫來匹配正則表達(dá)式,PCRE支持的正則表達(dá)式語法都能被MongoDB所接受。
MongoDB可以為前綴正則表達(dá)式(比如/^joey/)查詢創(chuàng)建索引,所以這種類型的查詢會非常高效。
正則表達(dá)式也可以匹配自身。雖然幾乎沒有人直接將正則表達(dá)式插入到數(shù)據(jù)庫中,但是萬一這么做了,也是可以用自身匹配的:
> db.foo.insert({"bar" : /baz/})
> db.foo.find({"bar" : /baz/})
查詢數(shù)組
數(shù)組絕大多數(shù)情況下可以這樣理解:每一個(gè)元素都是整個(gè)鍵的值。例如,如果數(shù)組是一個(gè)水果清單,比如下面這樣:
> db.food.insert({"fruit" : ["apple", "banana", "peach"]})
下面的查詢:
> db.food.find({"fruit" : "banana"})
會成功匹配該文檔。
①$all
通過多個(gè)元素來匹配數(shù)組,使用"$all"。
例如,假設(shè)創(chuàng)建包含3個(gè)元素的如下集合:
> db.food.insert({"_id" : 1, "fruit" : ["apple", "banana", "peach"]})
> db.food.insert({"_id" : 2, "fruit" : ["apple", "kumquat", "orange"]})
> db.food.insert({"_id" : 3, "fruit" : ["cherry", "banana", "apple"]})
要找到既有"apple"又有"banana"的文檔,就得用"$all"來查詢:
> db.food.find(fruit : {$all : ["apple", "banana"]})
db.food.insert({"_id" : 1, "fruit" : ["apple", "banana", "peach"]})
db.food.insert({"_id" : 3, "fruit" : ["cherry", "banana", "apple"]})
要是想查詢數(shù)組指定位置的元素,則需使用key.index語法指定下標(biāo),如:
> db.food.find({"fruit.2" : "peach"})
數(shù)組下標(biāo)從0開始,上面的表達(dá)式會用數(shù)組的第3個(gè)元素和"peach"匹配。
②$size
"$size"用于查詢指定長度的數(shù)組。例:
> db.food.find({"fruit" : {"$size" : 3}})
③$slice操作符
find的第二個(gè)參數(shù)是可選的,可以指定返回那些鍵。"$slice"返回?cái)?shù)組的一個(gè)子集合。
例如,假設(shè)現(xiàn)在有一個(gè)博客文章的文檔,要想反悔前10條評論,可以:
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : 10}})
也可以返回后10條評論,只要-10就可以了:
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -10}})
"$slice"也可以接受偏移值和要返回的元素?cái)?shù)量,來返回中間的結(jié)果:
> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : [23, 10]}})
這個(gè)操作會跳過前23個(gè)元素,返回第24個(gè)~第33個(gè)元素。如果數(shù)組不夠33個(gè)元素,則返回第23個(gè)元素后面的所有元素。
使用"$slice"默認(rèn)返回文檔中的所有鍵。
『查詢內(nèi)嵌文檔』
有兩種方法查詢內(nèi)嵌文檔:查詢整個(gè)文檔,或者只針對鍵/值對進(jìn)行查詢。
例,對于如下文檔:
{
"name" : {
"first" : "Joe"
"last" : "Schmoe"
},
"age" : 45
}
要查詢姓名為Joe Schmoe的人可以這樣:
> db.people.find({"name" : {"first" : "Joe", "last" : "Schmoe"}})
可以使用點(diǎn)表示法查詢內(nèi)嵌的鍵:
> db.people.find({"name.first" : {"first" : "Joe", "last" : "Schmoe"}})
例:假設(shè)有博客文章若干,要找到由Joe發(fā)表的5分以上的評論。要正確地指定一組條件,而不用指定每個(gè)鍵,要使用"$elemMatch"。這種模糊的命名條件句能用來部分指定匹配數(shù)組中的單個(gè)內(nèi)嵌文檔的限定條件:
> db.blog.find({"comments" : {"$elemMatch" : {"author" : "joe", "score" : {"$gte" : 5}}}})
"$elemMatch"將限定條件進(jìn)行分組,僅當(dāng)需要對一個(gè)內(nèi)嵌文檔的多個(gè)鍵操作時(shí)才會用到。
『$where查詢』
使用"$where"可以執(zhí)行任意JavaScript作為查詢的一部分。
最典型的應(yīng)用就是比較文檔中的兩個(gè)鍵的值是否相等。例如,有個(gè)條目列表,如果其中的兩個(gè)值相等則返回文檔。如下示例:
> db.foo.insert({"apple" : 1, "banana" : 6, "peach" : 3})
> db.foo.insert({"apple" : 8, "spinach" : 4, "watermelon" : 4})
第二個(gè)文檔中,"spinach"和"watermelon"的值相同,所以需要返回該文檔。MongoDB似乎用于不會提供一個(gè)$條件符來做這個(gè),所以只能用"$where"自居借助JavaScript來完成:
> db.foo.find({"$where" : function() {
for(var current in this) {
for(var other in this) {
if(current != other && this[current] == this[other]) {
return true;}
}
}
return false;
}});
如果函數(shù)返回true,文檔就作為結(jié)果的一部分被返回;如果為false,則不然。
也可以用一個(gè)字符串來指定"$where"查詢。下面兩種表達(dá)式是完全等價(jià)的:
> db.foo.find({"$where" : "this.x + this.y == 10"})
> db.foo.find({"$where" : "function() { return this.x + this.y == 10; }"})
"$where"在速度上比常規(guī)查詢慢很多。
『游標(biāo)』
要想從shell中創(chuàng)建一個(gè)游標(biāo),首先要對集合填充一些文檔,然后對其執(zhí)行查詢,并將結(jié)果分配給一個(gè)局部變量(用var生命的變量就是局部變量)。這里,先創(chuàng)建一個(gè)簡單的幾何,而后做個(gè)查詢,并用cursor變量保存結(jié)果:
> for(i=0; i<100; i++) {
db.collection.insert({x : i});
}
> var cursor = db.collection.find();
要跌待結(jié)果,可以使用游標(biāo)的next方法。也可以使用hasNext來查看有沒有其他結(jié)果。典型的結(jié)果遍歷如下:
> while (cursor.hasNext()) {
obj = cursor.next();
// do stuff
}
cursor.hasNext()檢查是否有后續(xù)結(jié)果存在,然后用cursor.next()將其獲得。
游標(biāo)類還實(shí)現(xiàn)了迭代器接口,可以在foreach循環(huán)中使用。
> var cursor = db.people.find()
> cursor.forEach(function(x) {
print(x.name);
});
『limit、skip和sort』
要限制結(jié)果數(shù)量,可在find后使用limit函數(shù)。例如,只返回3個(gè)結(jié)果,可以這樣:
> db.c.find().limit(3)
忽略掉前3個(gè)匹配的文檔,然后返回余下的文檔:
> db.c.find().skip(3)
sort用一個(gè)對象作為參數(shù):一組鍵/值對,鍵對應(yīng)文檔的別名,值代表排序的方向。排序方向可以是1(升序)或者-1(降序)。如果指定了多個(gè)鍵,則按照多個(gè)鍵的順序逐個(gè)排序。例如,要按照"username"升序及"age"降序排序,可以這樣寫:
> db.c.find().sort({username : 1, age : -1})
這3個(gè)方法可以組合使用。這對于分頁非常有用。例如,你有個(gè)在線商店,有人想搜索mp3。若是想每頁返回50個(gè)結(jié)果,而且按照價(jià)格從高到低排序,可以這樣寫:
> db.stock.find({"desc" : "mp3"}).limit(50).sort({"price" : -1})
點(diǎn)擊“下一頁”可以看到更多的結(jié)果,通過skip也可以非常簡單地實(shí)現(xiàn),只需要略過前50個(gè)結(jié)果就好了(已經(jīng)在第一頁顯示了):
> db.stock.find({"desc" : "mp3"}).limit(50).skip(50).sort({"price" : -1})
比較順序:MongoDB處理不同類型的數(shù)據(jù)有一個(gè)順序:
(1)最小值
(2)null
(3)數(shù)字(整型、長整型、雙精度)
(4)字符串
(5)對象/文檔
(6)數(shù)組
(7)二進(jìn)制數(shù)據(jù)
(8)對象ID
(9)布爾型
(10)日期型
(11)時(shí)間戳
(12)正則表達(dá)式
(13)最大值
『避免使用skip略過大量結(jié)果』
1.不用skip的結(jié)果進(jìn)行分頁
最簡單的分頁方法是用limit返回結(jié)果的第一頁,然后將每個(gè)后續(xù)頁面作為相對于開始的偏移量返回。
> // do not use: slow for large skips
> var page1 = db.foo.find(criteria).limit(100)
> var page2 = db.foo.find(criteris).skip(100).limit(100)
> var page3 = db.foo.find(criteris).skip(200).limit(100)
...
然而,一般來講可以找到一種方法實(shí)現(xiàn)不用skip的分頁,這取決于查詢本身。例如,要按照"date"降序顯示文檔,可以用如下方式獲取結(jié)果的第一頁:
> var page1 = db.foo.find().sort({"date" : -1}).limit(100)
然后,可以利用最后一個(gè)文檔中"date"的值作為查詢條件,來獲取下一頁:
var latest = null;
// dispaly first page
while (page1.hasNext()) {
latest = page1.next();
display(latest);
}
// get next page
vat page2 = db.foo.find({"date" : {"$gt" : latest.date}});
page2.sort({"date" : -1}).limit(100);
這樣查詢中就沒有skip了。
2.隨機(jī)選取文檔
例:想隨機(jī)找一個(gè)加州的水暖工,可以對"profession"、"state"和"random"建立索引:
> db.people.ensureIndex({"profession" : 1, "state" : 1, "random" : 1})
這樣就能很快得出一個(gè)結(jié)果了。
『高級查詢選項(xiàng)』
查詢分為包裝的和普通的兩類。
普通的查詢:
> var cursor = db.foo.find({"foo" : "bar"})
有幾個(gè)選項(xiàng)用于包裝查詢。例如,假設(shè)我們執(zhí)行一個(gè)排序:
> var cursor = db.foo.find({"foo" : "bar"}).sort({"x" : 1})
實(shí)際情況不是將{"foo" : "bar"}作為查詢直接發(fā)送給數(shù)據(jù)庫,而是將查詢包裝在一個(gè)更大的文檔中。shell會把查詢從{"foo" : "bar"}轉(zhuǎn)換成{"$query" : {"foo" : "bar"}}, "$orderby" : {"x" : 1}
絕大多數(shù)驅(qū)動(dòng)程序有些輔助措施向查詢添加各種選項(xiàng)。舉例:
· $maxscan : integer
指定查詢最多掃描的文檔數(shù)量
· $min : document
查詢的開始條件
· $max : document
查詢的結(jié)束條件
· $hint : document
指定服務(wù)器使用哪個(gè)索引進(jìn)行查詢
· $explain : boolean
獲取查詢執(zhí)行的細(xì)節(jié)(用到的索引、結(jié)果數(shù)量、耗時(shí)等),而并非真正執(zhí)行查詢。
· $snapshot : boolean
確保查詢的結(jié)果是在查詢執(zhí)行那一刻的一致快照
獲取一致結(jié)果:當(dāng)使用了"$snapshot"選項(xiàng),查詢就是針對不變的集合視圖運(yùn)行的。
游標(biāo)內(nèi)幕:客戶端游標(biāo)以及客戶端游標(biāo)表示的數(shù)據(jù)庫游標(biāo)。
?
轉(zhuǎn)載于:https://www.cnblogs.com/answernotfound/p/mongodbnote3.html
總結(jié)
以上是生活随笔為你收集整理的MongoDB学习笔记三:查询的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Library not loaded:
- 下一篇: 美化滚动条jquery.nicescro