MongoDB條件查詢

jx_yu發表於2015-01-13
  1. find({查詢條件限定},{返回欄位})  

這是一個查詢的基本語法,各個簽名的作用已經說得很清楚。下面來細細展開:

當然最開始插入一批資料以供測試:

Python程式碼  
  1. db.users.insert({"_id"1"name""aroba""age"22"friends"3})  
  2. db.users.insert({"_id"2"name""brob""age"23"friends"4})  
  3. db.users.insert({"_id"3"name""robin""age"24"friends"23})  
  4. db.users.insert({"_id"4"name""ccrob""age"25"friends"32})  
  5. db.users.insert({"_id"5"name""drobin""age"26"friends"15})  
  6. db.users.insert({"_id"6"name""rrobin""age""az""friends"19})  

 

1、 方法中的第一個引數:查詢條件限定是一個document結構,如為{}將預設返回所有資料

Python程式碼  
  1. #查詢一個年齡為27的使用者:  
  2. db.users.find({"age":23})  
  3. #查詢一個年齡為27,姓名為robin的使用者,相當於AND  
  4. db.users.find({"age":23"name":"brob"})  

作為文件的查詢條件,可以支援更復雜的格式:

Python程式碼  
  1. #查詢年齡大於20且小於30的使用者  
  2. db.users.find({"age":{"$gt":20"$lte":23}})  

這裡條件查詢有常用的:小於("$lt")、小於等於("$lte")、大於("$gt")、大於等於("$gte")、不等於("$ne") 。這些條件查詢對數字日期型別的欄位比較適用

 

前面說到同時查詢age和name屬性,相當於AND查詢。這裡來看看OR查詢,主要透過"$in"和"$or" 。對單一鍵有多個值與其匹配的話就用"$in",後面跟一個條件陣列。

Python程式碼  
  1. #查詢年齡在某個範圍的使用者:  
  2. db.users.find({"age":{"$in":[202225]}})  

"$in" 對支援的型別非常靈活,不同型別的條件可以同時查詢。與之相對應的就是"$nin",表示不在該範圍內的鍵

Python程式碼  
  1. db.users.find({"age":{"$in":[202225"az"]}})  
  2. db.users.find({"age":{"$nin":[202225"az"]}})  

 與單一鍵的"$in"不同的是,"$or"是包含多個可能條件的陣列。

Python程式碼  
  1. #年齡在某個範圍內或者name在某個範圍內的使用者  
  2. db.users.find({"$or": [{"age"23 }, {"name""robin"}]})  
  3. db.users.find({"$or": [{"age": {"$in": [ 234"az" ]} }, {"name""robin"}]})  

 

2、返回欄位

作為查詢的第二個引數,如果沒有的話是預設返回所有欄位。可以對需要的返回欄位指定:

Python程式碼  
  1. db.users.find({}, {"name":1"age":1})  

1、這個查詢會返回name、age、_id欄位
2、_id是預設返回,如果不要顯示加上("_id":0)     

Python程式碼  
  1. db.users.find({}, {"name":1"age":1"_id":0})  

3、如果某個欄位如age不存在,也不拋異常
4、需要顯示的欄位設定為大於零的數就可以,但還是用1好理解,但如果對不需要顯示的欄位且不是_id設定為0或其他會拋異常

Python程式碼  
  1. db.users.find({}, {"name":1"age":0"_id":0})  

 這樣是不行的,如果不要返回age不加上就可以了

後面還將對陣列查詢的返回欄位做相應的說明,這裡就先到此

 

3、幾點說明

1、"$not"元條件句,用在其他任何條件上,如

Python程式碼  
  1. #age>20即查詢age小於等於20的使用者  
  2. db.user.find({"age": {"$not" : {"$gt" :20}}})    
  3. #這裡查詢age不是1,6,11,16...等的使用者  
  4. db.user.find({"age": {"$not": {"$mod": [51]}}})   

 

2、條件查詢與更新修改器

Python程式碼  
  1. #更新修改器  
  2. db.users.update({"age"23},{"$set":{"name":"zzzz"}})  
  3. #條件查詢  
  4. db.users.find({"age": {"$gt"20}})   

條件句是內層文件鍵,修改器是外層文件鍵。而且對同一個欄位age來說可以是多個限定條件,但是修改器不能對應多個

 

3、null
如果某個欄位的值為null,根據null來查詢時可以返回該條文件,但也會返回不包含該欄位的文件

Python程式碼  
  1. #新增兩條資料  
  2. >db.users.insert{ "_id" : 7"age" : 23"name" : "joe" }  
  3. >db.users.insert{ "_id" : 8"age" : 24"friends" : null, "name" : "sam" }  

 查詢鍵值為null的欄位

Python程式碼  
  1. >db.users.find({"friends": null})。  

 這裡會返回friends為null的文件,但是也會返回沒有該鍵的文件

 

Shell程式碼  
  1. "_id" : 7"age" : 23"name" : "joe" }  
  2. "_id" : 8"age" : 24"friends" : null, "name" : "sam" }  

 需要透過"$exists"來判定鍵值是否存在

Shell程式碼  
  1. > db.users.find({"friends":{"$in":[null],"$exists":true}})  
  2. "_id" : 8"age" : 24"friends" : null, "name" : "rrbin" }  

 

4、正規表示式

Shell程式碼  
  1. #這裡會返回所有name中包含rob欄位的文件  
  2. > db.users.find({"name":/rob/})  
  3. #不僅對欄位值進行正則匹配,如果值本身是正則式也匹配  

 

 

4、陣列查詢

插入幾條資料測試

Python程式碼  
  1. db.food.insert({"_id"1"fruit": ["apple""banana""peach"]})  
  2. db.food.insert({"_id"2"fruit": ["apple""orange"]})  
  3. db.food.insert({"_id"3"fruit": ["banana""peach""orange"]})  

以下是一些常用的查詢方法,直接上

Python程式碼  
  1. #匹配fruit中包含banana的文件  
  2. db.food.find({"fruit""banana"})  
  3. #必須匹配所有  
  4. db.food.find({"fruit": {"$all" : ["apple""peach"]}})  
  5. #精確匹配  
  6. db.food.find({"fruit": ["apple""orange"]})  
  7. #指定下標 key.index  
  8. db.food.find({"fruit.2""peach"})  
  9. #查詢指定長度的陣列  
  10. db.food.find({"fruit": {"$size" : 3}})  

但是"$size"操作只能嚴格匹配,遇到比如要求陣列大於或者小於之類的查詢就無能為力了。這裡提供瞭解決的方案:對文件新增size欄位,每次對陣列push或pop操作時,對size欄位做相應的增減。查詢的時候再對欄位size做相應的處理

Python程式碼  
  1. db.food.update({"$push" :{"fruit" : "strawberry"} , "$inc" : {"size" : 1}})  
  2. db.food.find({"size" : {"$gt" : 3}})  

 

返回陣列指定子集
"$slice"用於返回陣列的一個子集,支援前、後或者偏移

Python程式碼  
  1. db.food.insert({"_id"4"fruit": ["apple""banana""peach""orange""watermelon""lemon""cherry"]})  
  2. #取前2個  
  3. db.food.find({"_id":4}, {"fruit":{"$slice":2}})  
  4. #{u'_id': 4, u'fruit': [u'apple', u'banana']}  
  5. #取後兩個  
  6. db.food.find({"_id":4}, {"fruit":{"$slice":-2}})  
  7. #{u'_id': 4, u'fruit': [u'lemon', u'cherry']}  
  8. #從第2個開始取三個,這個其實達到分頁的效果,但書中明確指出對大量資料skip效能下降厲害,不建議考慮這種方式  
  9. db.food.find({"_id":4}, {"fruit":{"$slice":[23]}})  
  10. #{u'_id': 4, u'fruit': [u'peach', u'orange', u'watermelon']}  

 使用"$slice"獲取陣列內的值時,其他的鍵也會預設返回,如果不需要返回非陣列內的其他鍵這裡可以指明,與前面返回不同的是這裡可以用0

Python程式碼  
  1. db.food.insert({"_id"5"sum":7"fruit": ["apple""banana""peach""orange""watermelon""lemon"]})  
  2. db.food.find({"_id":5}, {"fruit":{"$slice":[23]}, "_id":0"sum":0})  
  3. {u'fruit': [u'peach', u'orange', u'watermelon']}  

 

5、查詢內嵌文件

這裡主要考慮匹配查詢內嵌文件,考慮如下文件

Python程式碼  
  1. db.users.insert({"_id"9"age":23"name": {"first":"joe""last":"sam"}})  
  2. db.users.insert({"_id"10"age":24"name": {"first":"joe""middle":"dd""last":"sam"}})  

查詢名字為joe sam的使用者

Python程式碼  
  1. #查詢名字為joe sam的使用者  
  2. data = db.users.find({"name":{"first":"joe""last":"sam"}})  
  3. #返回第一條,實際上這相當於精確匹配,這個查詢條件將嚴格匹配順序、欄位的數量。其實第二條也是我們想要的結果,那麼正確的寫法應該是:  
  4. data = db.users.find({"name.first":"joe""name.last":"sam"})  

 書中說到一種複雜情況下的查詢:joe發表的5分以上的評論:

Python程式碼  
  1. db.blog.insert({"_id":1"content":"....""comments":[{"name":"joe""score":3"comment":"nice"}, {"name":"sam""score":5"comment":"zzz"}, {"name":"joe""score":5"comment":"good"}]})  
  2. data = db.blog.find({"comments":{"name":"joe""score":{"$gte":5}}})  
  3. #這樣是查不到資料的,內嵌文件要求匹配整個文件,而不是comments鍵  
  4. data = db.blog.find({"comments.name":"joe""comments.score":{"$gte":5}})  
  5. #這個查詢會返回這條記錄,其實是匹配的commets中各個鍵,即joe匹配第一條,score匹配第二條  
  6. data = db.blog.find({"comments":{"$elemMatch":{"name":"joe""score":{"$gte":5}}}})  

 

 

6、分頁

分頁在前面說到"$slice"時,其實是達到分頁的效果,前面也說了弊端,這裡進一步說明。這裡採用limit限制返回結果,slice跳過指定數量文件,sort對查詢結果排序

limit
db.users.find().limit(3)結果集超過三條返回三條,不足返回實際數量,貌似對負數不感冒,比如-2還是返回前兩條,或者limit裡沒有偏移這個概念
skip
db.users.find().limit(3)省略結果集前三個,返回剩下的,結果集不足三個就啥都木有了,當然這個也一樣,別寫負數了,否則拋異常
sort
對結果集排序:1升序,-1降序。可支援多個鍵/對

Python程式碼  
  1. db.users.find().sort([("name"1), ("age", -1)])  
Shell程式碼  
  1. db.users.find().sort({"name":1,"age":-1})  
Python程式碼  
  1. #這就是分頁  
  2. db.users.find().limit(2).sort("_id"1)  
  3. db.users.find().limit(2).skip(2).sort("_id"1)  
  4. db.users.find().limit(2).skip(4).sort("_id"1)  

這對大資料量的skip效能影響較大,這裡也提供了一些繞過的方法。比如先取得最後一條的記錄的某個唯一鍵,再查詢大於該鍵的值。可以看出這個限制條件挺多,當然容易想到的採用主鍵"_id",這是主鍵必須是數字了

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/27000195/viewspace-1400265/,如需轉載,請註明出處,否則將追究法律責任。

相關文章