MongoDB中使用find來進行查詢。查詢就是返回一個集合中文檔的子集,子集的範圍從0個文檔到整個集合。find中的第一個參數決定了要返回的哪些文檔,這個參數是一個文檔,用於指定查詢條件。javascript
空的查詢文檔(例如{})會匹配集合的所有內容。要不是指定查詢文檔,默認就是{}. 例如:java
> db.c.find()
將批量返回集合c中全部的文檔。正則表達式
使用條件數據庫
> db.users.find({"age": 27})
有時並不須要將文檔中全部的鍵/值對都返回。遇到這種狀況,能夠經過find、findOne的第二參數來指定想要的鍵。這樣作機會節省傳輸的數據量,又能節省客戶端解碼文檔的時間和內存消耗。數組
例如,若是隻對用戶集合的「username」和"email"鍵感興趣,可使用以下方式返回這些鍵:服務器
> db.users.find({}, {"username": 1, "email": 1})
這種狀況默認"_id"這個鍵老是被返回的,即便沒有指定要返回這個鍵。app
若是咱們不但願結果中含有"fatal_weakness"鍵那麼能夠以下操做:函數
> db.users.find({}, {"username": 1, "_id": 0})
這樣就能夠把"_id"鍵剔除掉。post
當查詢時,傳遞給數據庫的查詢文檔的值必須是常量。也就是不能引用文檔中其餘鍵的值。例如保存庫存有"in_stock"(剩餘庫存)和"num_sold"(已出售)兩個鍵,想經過下列查詢比較是行不通的。優化
> db.stock.find({"in_stock": "this.num_sold"})
"$lt","$lte","$gt"和"$gte"就是所有的比較操做符,分別對應<、<=、>、和>=。能夠將其組合起來以便查找一個範圍的值。例如查找18-30歲(含)的用戶,就能夠像下面這樣
>db.users.find({"age": {"$gte": 18, "lte": 30}})
這樣就能夠找到"age"字段大於等於18,小於等於30的全部文檔。
這樣的範圍查詢對日期極爲有用。例如要查找在2007年1月1日前註冊的人,能夠像下面這樣。
> start = new Date("01/01/2007") > db.users.find({"registered": {"$lt": start}})
若是是想查詢文檔的某個鍵/值不等於某個特定值的狀況下,就要使用另外一種條件操做符「$ne」,它表示不相等,如果想查詢全部名字部位joe的用戶,就能夠以下查詢
> db.users.find({"username": {"$ne": "joe"}})
MongoDB中有兩種方式進行OR查詢: "$in"能夠用來查詢一個鍵的多個值;"$or"更通用一些,能夠在多個鍵中查詢任意的給定值。
> db.raffle.find({"ticker_no": {"$in": [725, 542, 390]}})
"$in"很是靈活能夠指定不一樣類型的條件和值。例如,在逐步將用戶的ID好前已成用戶名的過程當中,查詢須要同時匹配ID和用戶名:
這會匹配"user_id"等於12345的文檔,也會匹配"user_id"等於"joe"的文檔。
要是"$in"對應的數組只有一個值,那麼和直接匹配這個值的效果同樣例如 {ticket_no: {"$in": [725]}} 和 {"ticker_no": 725} 效果同樣。
與"$in"相對的是"$nin","$nin"將返回與數組中全部的條件都不匹配的文檔好比:
> db.raffle.find({"ticket_no": {"$nin": [725, 543, 490]}})
"$in"能夠對單個鍵作OR 查詢,但想要找到"ticket_no"爲725或者"winner"爲true的文檔應該怎麼辦呢?對於這種狀況可使用 $or
> db.raffle.find({"$or": [{"ticket_no": 725}, {"winner": true}]})
還能夠這樣使用:
> db.raffle.find({"$or": [{"ticket_no": {"$in": [725, 345, 789]}},{"winner": true}]})
"$not"是元條件語句,便可以用在任何其餘條件之上。就拿取模運算符"$mod"來講。"$mod"會將查詢的值除以第一個給定值,若餘數等於第二個給定值則匹配成功:
> db.users.find({"id_num": {"$mod: [5, 1]}})
上面的查詢會返回"id_num"值爲1,6,11,16等用戶。可是要想返回"id_num"爲二、三、四、五、七、八、九、10等用戶就要使用"$not"了:
>db.users.find({"id_num": {"$not": {"$mod": [5, 1]}}})
若是比較一下更新修改器和前面的查詢文檔,就會發現以$開頭的鍵位於在不一樣的位置。在查詢中,"$lt"在內層文檔,而更新中"$inc"則是外層文檔的鍵。基本能夠確定:條件語句是內層文檔的鍵,而修改器則是外層文檔的鍵。
能夠對一個鍵應用多個條件。例如,要查找年齡爲20~30的全部用戶,能夠在"age"鍵上使用"$gt"和"$lt":
> db.users.find({"age": {"$lt": 30, "$gt": 20}})
一個鍵能夠有任意多個條件,可是一個鍵不能對應多個修改器。例如,修改器文檔不能勇士含有{"$inc": {"age": 1}, {"$set": {"age": 40}}},由於修改了"age"兩次。可是對於查詢條件句就沒有這種限定。
有一些元操做符也位於外層文檔中,好比"$and"、"$or"和"$nor"。他們的使用形式相似:
>db.users.find({"$and": [{"x": {"$lt": 1}}, {"x": 4}]})
這個會查詢匹配哪些"x"字段的值小於1而且等於4的文檔,雖然看起來是矛盾的,可是徹底是可能的,好比,若是"x"字段的值是這樣的一個{"x": [0, 4]},那麼這個文檔就與查詢條件匹配,可是查詢優化器不會對"$and"進行優化,這與其餘操做符不一樣。若是把上面的查詢改爲下面這樣,效率更加高
>db.users.find({"x": {"$lt": 1, "$in": [4]}})
在MongoDB中有一些在查詢時會有特殊的表現
null類型的行爲有點奇怪他能夠匹配自身,因此有一個包含以下文檔的集合:
> db.c.find() { "_id" : ObjectId("5cd17b2891b417d2e2ad7467"), "y" : null } { "_id" : ObjectId("5cd17b2891b417d2e2ad7468"), "y" : 1 } { "_id" : ObjectId("5cd17b2891b417d2e2ad7469"), "y" : 2 }
就能夠按照預期的方式查詢"y"鍵爲null的文檔:
> db.c.find({"y": null}) { "_id" : ObjectId("5cd17b2891b417d2e2ad7467"), "y" : null }
可是null不只會匹配某個鍵的值爲null的文檔,並且還會匹配不包含這個鍵的文檔,因此這種匹配還會返回缺乏這個鍵的全部文檔:
> db.c.find({"z": null}) { "_id" : ObjectId("5cd17b2891b417d2e2ad7467"), "y" : null } { "_id" : ObjectId("5cd17b2891b417d2e2ad7468"), "y" : 1 } { "_id" : ObjectId("5cd17b2891b417d2e2ad7469"), "y" : 2 }
若是僅想匹配鍵值爲null的文檔,既要檢查該鍵的值是否爲null,還要經過"$exists"判斷這個鍵值是否是存在:
> db.c.find({"z": {"$in": [null], "$exists": true}})
由於沒有 "$eq"因此使用"$in"效果是同樣的
正則表達式能夠靈活有效的匹配字符串。例如,想要查找全部名爲Joe或者joe的用戶,就可使用正則表達式執行不區分大小寫的匹配:
> db.users.find({"name": /joe/i})
系統能夠接受正則表達式的標誌(i),可是不是必定要有。如今已經匹配了各類大小寫組合形式的joe,若是還但願匹配"joey"這樣的值,那麼能夠稍微修改一下
> db.users.find({"name": /joe?/i})
正則表達式也能夠匹配自身
查詢數組與查詢標量的值是同樣的。例若有一個水果列表,以下所示:
> db.food.insert({"friut": ["apple", "banana", "peach"]})
下面查詢:
> db.food.find({"friut": "banana"}) { "_id" : ObjectId("5cd17ef091b417d2e2ad746e"), "friut" : [ "apple", "banana", "peach" ] }
會成功匹配這個文檔,好像咱們在查詢一個不合法的文檔: {"fruit": "apple", "fruit": "banana", "fruit": "peach"}
> db.food.find() { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7470"), "fruit" : [ "apple", "kumquat", "orange" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7471"), "fruit" : [ "cherry", "banana", "apple" ] }
咱們要找到既有"apple"又有"banana"的文檔,可使用"$all"來查詢:
> db.food.find({"fruit": {"$all": ["apple", "banana"]}}) { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7471"), "fruit" : [ "cherry", "banana", "apple" ] }
若是想查詢數組特定位置的元素,需使用key.index語法指定下標:
> db.food.find({"fruit.2": "peach"}) { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] }
「$size」對於查詢數組來講也很是有用。顧名思義,能夠用它來查詢特定長度的數組。例如:
> db.food.find({"fruit": {"$size": 3}}) { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7470"), "fruit" : [ "apple", "kumquat", "orange" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7471"), "fruit" : [ "cherry", "banana", "apple" ] }
獲得一個長度範圍內的文檔是一種常見的查詢。"$size"並不能與其餘查詢條件(「$gt」)聯合使用,可是這用查詢能夠在文檔中添加一個"size"字段來時間每次"$push", 「size」字段就加一,以後能夠對這個字段進行查詢。
> db.food.update(criteria, {"$push": {"fruit": "strawbery"}, {"$inc": {"size": 1}}})
可是這種技巧不能和"$addToSet" 操做符同時使用
find的第二個參數是可選的,能夠指定須要返回的鍵。這個特別的"$slice"操做符能夠返回某個鍵匹配的數組元素的一個子集。
加入,假設如今有一個博客文章的文檔,咱們但願返回前十條評論能夠這樣作:
> db.blog.posts.findOne(criteria, {"comments": {"slice": 10}})
也能夠返回後面10條評論,只要在查詢條件中使用-10就能夠了:
> db.blog.posts.findOne(criteria, {"comments": {"slice": -10}})
"$slice"也能夠指定偏移值以及但願返回的元素的數量,來返回元素集合中間位置的某些結果:
> db.blog.posts.findOne(criteria, {"comments": {"$slice": [23, 10]}})
這個操做會跳過前23個元素,返回第24~33個元素。若是數組不夠33個元素,則返回第23個元素後面的全部元素。
若是知道元素的下標,那麼"$slice"很是有用。可是有時咱們但願返回與查詢條件相匹配的任意一個數組元素。可使用$操做符獲得一個匹配的元素。對於上面的博客文章示例,能夠用以下的方式獲得Bob的評論:
> db.blogs.find({"comments.name": "bob"}, {"comments.$": 1}) { "_id": ObjectId("dfadfafajkldflajdfk32230942903"), "comments" : { "name": "bob", "email": "bob@example.com", "content": "good post" } }
注意這樣只會返回第一個匹配的文檔。若是Bob在這篇博客文章下寫過多條評論,只有「comments」數組中的第一條評論會被返回
文檔中的標量(非數組元素)必須與查詢條件中的每一條語句想匹配。例如,若是使用{"x": {"$gt": 10, "$lt": 20}}進行查詢,只會匹配"x"鍵的值大於10 而且小於20的文檔。可是,加入某個文檔的"x"字段是一個數組,若是"x"鍵的某個一元素與查詢條件的任意一條語句相匹配(查詢條件中的每條語句能夠匹配不一樣的數組元素),那麼這個文檔也會被返回。
下面用一個例子來詳細說明這種狀況。假若有以下所示的文檔:
> db.test.find() { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b37"), "x" : 5 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b38"), "x" : 15 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b39"), "x" : 25 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b3a"), "x" : [ 5, 25 ] }
若是但願找到"x"鍵位於10和20之間的全部文檔,直接想到的查詢方式是使用
> db.test.find({"x": {"$lt": 20, "$gt": 5}}) { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b38"), "x" : 15 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b3a"), "x" : [ 5, 25 ] }
5和25都不位於10和20之間,可是這個文檔也返回了,由於25與條件查詢中的第一個語句(大於10)相匹配5與查詢條件中的第二個語句(小於20)相匹配。
這使對數組使用範圍查詢沒有用:範圍會匹配任意多元素數組。有幾種凡是能夠獲得預期的行爲。
首先,可使用"$elemMatch"要求同時使用查詢條件中的兩個語句與一個數組元素比較,可是這個有一個問題,"elemMatch"不會匹配費數組元素:
> db.test.find({"x": {"elemMatch": {"$gt": 10, "$lt": 20}}}) >
不會和{"x": 15}相匹配了,由於只查詢數組了。
若是當前查詢的字段上建立過索引可使用min,max將查詢條件遍歷的索引範圍限制爲"$gt","$lt"的值:
> db.test.find({"x": {"$gt": 10, "$lt": 20}}).min({"x": 10}).max({"x": 20}) {"x": 15}
查詢內嵌文檔
簡單的查詢
>db.people.find({"name.first": "Joe", "name.last": "Schmoe"})
可是當文檔結構變得更加複雜以後,內嵌文檔的匹配須要一些技巧。例如假設有博客文章若干,要找到Joe發表的5分以上的評論。博客文章的結構以下例所示:
> db.blog.find() { "content": "...", "comments": [ { "author": "joe", "score": 3, "comment": "nice post" }, { "author": "mary", "score": 5, "comment": "terrible post" } ] }
直接用 > db.blog.find({"comments": {"author": "joe", "score": {"$gte": 5}}}) 也不行由於符合author條件的評論和score條件的評論可能不是同一條評論。也就是說,會返回剛纔顯示的那個文檔,由於「author」: joe 在第一條評論中匹配了,"score": 6在第二條評論中匹配了
要準確的指定一組條件,而沒必要指定每一個鍵,就須要使用"elemMatch".。
> db.blog.find("comments": {"$elemMatch": {"author": "joe", "score": {"$gte": 5}}})
可使用任何的JavaScript代碼
> db.foo.find({"$where": function() { .... }})
若是函數返回true文檔就做爲結果集的一部分返回;若是爲false就不返回。
限制返回結果的數量,忽略必定數量的結果以及排序,全部這些選項必定要在查詢被髮送到服務器以前指定。
先限制結果數量,可在find後使用limit函數,例如只返回3個結果,能夠這樣:
> db.c.find().limit(3)
要是匹配的結果不到三個,則返回匹配的數量。limit指定的是數量上限而非下限。
skip和limit類似
>db.c.find().skip(3)
上面的操做會略過前三個匹配的文檔,而後返回餘下的文檔。若是集合裏面能匹配的文檔少於3個,則不會返回任何文檔。
sort 接受一個對象做爲參數,這個對象是一組鍵/值對,鍵對應文檔的鍵名,只表明排序的方向。排序方向能夠是1(升序)或者是-1(降序)。若是指定了多個鍵,則按照這些鍵被指定的順序逐個排序,例如按照"username"升序及"age"降序排序,能夠這樣寫:
>db.c.find().sort({"username": 1, "age": -1})
這三個方法能夠組合使用。
對鍵的排序是有優先級的,順序以下: