上一篇文章: MongoDB指南---六、更新文檔
下一篇文章: MongoDB指南---八、特定類型的查詢
本章將詳細介紹查詢。主要會涵蓋如下幾個方面:正則表達式
MongoDB中使用find來進行查詢。查詢就是返回一個集合中文檔的子集,子集合的範圍從0個文檔到整個集合。find的第一個參數決定了要返回哪些文檔,這個參數是一個文檔,用於指定查詢條件。
空的查詢文檔(例如{})會匹配集合的所有內容。要是不指定查詢文檔,默認就是{}。例如:數據庫
> db.c.find()
將批量返回集合c中的全部文檔。
開始向查詢文檔中添加鍵/值對時,就意味着限定了查詢條件。對於絕大多數類型來講,這種方式很簡單明瞭。數值匹配數值,布爾類型匹配布爾類型,字符串匹配字符串。查詢簡單的類型,只要指定想要查找的值就行了,十分簡單。例如,想要查找"age"值爲27的全部文檔,直接將這樣的鍵/值對寫進查詢文檔就行了:segmentfault
> db.users.find({"age" : 27})
要是想匹配一個字符串,好比值爲"joe"的"username"鍵,那麼直接將鍵/值對寫在查詢文檔中便可:數組
> db.users.find({"username" : "joe"})
能夠向查詢文檔加入多個鍵/值對,將多個查詢條件組合在一塊兒,這樣的查詢條件會被解釋成「條件1AND條件2AND ... AND條件N」。例如,要想查詢全部用戶名爲joe且年齡爲27歲的用戶,能夠像下面這樣:函數
> db.users.find({"username" : "joe", "age" : 27})
有時並不須要將文檔中全部鍵/值對都返回。遇到這種狀況,能夠經過find(或者findOne)的第二個參數來指定想要的鍵。這樣作既會節省傳輸的數據量,又能節省客戶端解碼文檔的時間和內存消耗。
例如,若是隻對用戶集合的"username"和"email"鍵感興趣,可使用以下查詢返回這些鍵:性能
> db.users.find({}, {"username" : 1, "email" : 1}) { "_id" : ObjectId("4ba0f0dfd22aa494fd523620"), "username" : "joe", "email" : "joe@example.com" }
能夠看到,默認狀況下"_id"這個鍵老是被返回,即使是沒有指定要返回這個鍵。
也能夠用第二個參數來剔除查詢結果中的某些鍵/值對。例如,文檔中有不少鍵,可是咱們不但願結果中含有"fatal_weakness"鍵:優化
> db.users.find({}, {"fatal_weakness" : 0})
使用這種方式,也能夠把"_id"鍵剔除掉:this
> db.users.find({}, {"username" : 1, "_id" : 0}) { "username" : "joe", }
查詢的使用上有些限制。傳遞給數據庫的查詢文檔的值必須是常量。(在你本身的代碼裏能夠是正常的變量。)也就是不能引用文檔中其餘鍵的值。例如,要想保持庫存,有"in_stock"(剩餘庫存)和"num_sold"(已出售)兩個鍵,想經過下列查詢來比較二者的值是行不通的:code
> db.stock.find({"in_stock" : "this.num_sold"}) // 這樣是行不通的
的確有辦法實現相似的操做(詳見4.4節),但一般須要略微修改一下文檔結構,就能經過普通查詢來完成這樣的操做了,這種方式性能更好。在這個例子中,能夠在文檔中使用"initial_stock"(初始庫存)和"in_stock"兩個鍵。這樣,每當有人購買物品,就將"in_stock"減去1。這樣,只須要用一個簡單的查詢就能知道哪一種商品已脫銷:排序
> db.stock.find({"in_stock" : 0})
查詢不只能像前面說的那樣精確匹配,還能匹配更加複雜的條件,好比範圍、OR子句和取反。
"$lt"、"$lte"、"$gt"和"$gte"就是所有的比較操做符,分別對應<、<=、>和>=。能夠將其組合起來以便查找一個範圍的值。例如,查詢18~30歲(含)的用戶,就能夠像下面這樣:
> db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
這樣就能夠查找到"age"字段大於等於1八、小於等於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"能用於全部類型的數據。
MongoDB中有兩種方式進行OR查詢:"$in"能夠用來查詢一個鍵的多個值;"$or"更通用一些,能夠在多個鍵中查詢任意的給定值。
若是一個鍵須要與多個值進行匹配的話,就要用"$in"操做符,再加一個條件數組。例如,抽獎活動的中獎號碼是72五、542和390。要找出所有的中獎文檔的話,能夠構建以下查詢:
> db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})
"$in"很是靈活,能夠指定不一樣類型的條件和值。例如,在逐步將用戶的ID號遷移成用戶名的過程當中,查詢時須要同時匹配ID和用戶名:
> db.users.find({"user_id" : {"$in" : [12345, "joe"]})
這會匹配"user_id"等於12345的文檔,也會匹配"user_id"等於"joe"的文檔。
要是"$in"對應的數組只有一個值,那麼和直接匹配這個值效果同樣。例如,{ticket_no : {$in:[725]}}和{ticket_no : 725}的效果同樣。
與"$in"相對的是"$nin","$nin"將返回與數組中全部條件都不匹配的文檔。要是想返回全部沒有中獎的人,就能夠用以下方法進行查詢:
> db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}})
該查詢會返回全部沒有中獎的人。
"$in"能對單個鍵作OR查詢,但要是想找到"ticket_no"爲725或者"winner"爲true的文檔該怎麼辦呢?對於這種狀況,應該使用"$or"。"$or"接受一個包含全部可能條件的數組做爲參數。上面中獎的例子若是用"$or"改寫將是下面這個樣子:
> db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]})
"$or"能夠包含其餘條件。例如,若是但願匹配到中獎的"ticket_no",或者"winner"鍵的值爲true的文檔,就能夠這麼作:
> db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}}, {"winner" : true}]})
使用普通的AND型查詢時,老是但願儘量用最少的條件來限定結果的範圍。OR型查詢正相反:第一個條件應該儘量匹配更多的文檔,這樣纔是最爲高效的。
"$or"在任何狀況下都會正常工做。若是查詢優化器能夠更高效地處理"$in",那就選擇使用它。
"$not"是元條件句,便可以用在任何其餘條件之上。就拿取模運算符"$mod"來講。"$mod"會將查詢的值除以第一個給定值,若餘數等於第二個給定值則匹配成功:
> db.users.find({"id_num" : {"$mod" : [5, 1]}})
上面的查詢會返回"id_num"值爲一、六、十一、16等的用戶。但要是想返回"id_num"爲二、三、四、五、七、八、九、十、12等的用戶,就要用"$not"了:
> db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}})
"$not"與正則表達式聯合使用時極爲有用,用來查找那些與特定模式不匹配的文檔(4.3.2節會詳細講述正則表達式的使用)。
若是比較一下上一章的更新修改器和前面的查詢文檔,會發現以$開頭的鍵位於在不一樣的位置。在查詢中,"$lt"在內層文檔,而更新中"$inc"則是外層文檔的鍵。基本能夠確定:條件語句是內層文檔的鍵,而修改器則是外層文檔的鍵。
能夠對一個鍵應用多個條件。例如,要查找年齡爲20~30的全部用戶,能夠在"age"鍵上使用"$gt"和"$lt":
> db.users.find({"age" : {"$lt" : 30, "$gt" : 20}})
一個鍵能夠有任意多個條件,可是一個鍵不能對應多個更新修改器。例如,修改器文檔不能同時含有{"$inc" : {"age" : 1}, "$set" : {age : 40}},由於修改了"age"兩次。可是對於查詢條件句就沒有這種限定。
有一些「元操做符」(meta-operator)也位於外層文檔中,好比"$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指南---六、更新文檔
下一篇文章: MongoDB指南---八、特定類型的查詢