mongodb筆記——查詢

mongodb筆記——更新

本文爲mongodb關於查詢操作的知識點,更新操作的請查看上方鏈接。

以下舉例操作集合爲以下格式

student集合(不要太在意這表的設計,只是爲方便舉例而已)

_id name age sex score books
123 張三 20 man [{name:"語文",score:90},{name:"英語",score:90},{name:"數學",score:90}] ["java","OC","js","mongodb"]

1、普通查詢

mongodb使用的是bson,使用上跟jison幾乎無異,在使用查詢上基本跟操作對象差不多
(1)查所有數據
db.student.find()

(2)只查詢指定的字段
db.student.find({},{name:1})

db.student.find({},{name:0})


上面例子中第一個{}爲條件,第二個爲要查詢的字段0爲不顯示,1爲顯示。
第一條查詢結果只顯示_id和name,如要_id也不顯示則需要指明_id不顯示(即{name:1,_id:0}),第二條的查詢結果則爲除了name,其他的都顯示。

2、簡單條件查詢

(1)等於查詢
db.student.find({age:20})

db.student.find({age:20},{name:1,sex:1})

第一條語句查詢所有age等於20的數據,且顯示所有字段。第二條語句則是查詢age等於20的數據,且只顯示_id,name和sex

(2)範圍查詢
從上面的例子可看出所有的數據操作中是以鍵值對的形式操作的,所以很明顯mongdb不能>,<,!=等這些比較符,而是使用以下比較符
sql mongdb
> $gt
< $lt
>= $gte
<= $lte
!= $ne
in $in
not in $nin

例子
//age不等於20的記錄
db.student.find({age:{$ne:20}});

//age等於19,20,21的記錄
db.student.find({age:{$in:[19,20,21]}});

3、多條件查詢

多條件查詢連接符無非就是and 和 or 操作
and操作在mongodb中很簡單,他的查詢條件爲鍵值對(個人理解爲JS中對象的操作,即如查age=20,name=張三的記錄則是傳個對象student,其age屬性爲20,name爲張三,所以爲{age:20,name:"張三"}。同理可得or操作,則需要多個對象,如查age爲20,或name爲張三的記錄,則需{age:20}和{name:“張三”}兩個對象,這個瞭解持久層框架的同學應該很容易理解的),所以and多條件查詢,只需將條件用,隔開即可。
而or不要嘗試也用,隔開如db.student.find({age:21,age:20}),這句的查詢結果只爲age=20的記錄,要進行or查詢則需要操作符$or,進行連接
例子:
//查詢age=20 and name=zhangsan
db.student.find({name:"zhangsan",age:20});

//查詢age=20 or name=zhangsan
db.student.find($or:[{name:"zhangsan"},{age:20}]);

//查詢age=20 or (name=zhangsan and age=21)
db.student.find($or:[{age:20},{name:"zhangsan",age:21}]);

//查詢age=20 and (name=zhangsan or name=lisi)
db.student.find({age:20,$or:[{name:"zhangsan"},{name:"lisi"}]})

4、模糊查詢

模糊查詢,mongodb並沒有sql的like語句,但相對應的它支持更強大的正則表達式,使用正則表達式進行模糊查詢,有兩種方式第一種關鍵注意點1、不需要 “ ”,2、使用 /  開始和結束標記。第二種使用關鍵詞$regex
例:
//name包含“李”字
db.student.find({name:/李/})

//name包含“李”字,第二種寫法
db.student.find({name:{$regex:"李"}})


//name爲z開頭,n結尾
db.student.find({name:/^z.*n$/})

//name不含有"李"字
db.student.find({name:{$not:/李/}})










5、複雜查詢,可使用$where

mongodb可使用js語句,在做複雜查詢的時候,可以使用js進行篩選,db.student.find({$where:function(){}}),其中function返回true則爲所需要的記錄。例
//查詢數學成績大於80的記錄
db.student.find({$where:function{
    var score=null;
    for(var i=0;i<this.score.length;i++){
        score=this.score[i];
        if(score.name==="數學" && score.score>80){
           return true;
        }
     }
     return false;
}});








上面的this爲集合中的一條記錄。(mongodb叫decument,在本文中因爲sql的習慣,有些地方都沒使用mongodb的名詞,大家理解就行了,像數據表mongodb叫集合)

6、遊標  

上面說了,mongodb在shell中支持js,那麼當我們執行語句 var s=db.student.find(); 後,s不是爲student數組而是遊標,但也支持使用s[i]來獲取對應的記錄。
需要注意以下幾點:
(1)獲取記錄的數量:s.size(),s.length(),s.count(),都可以獲取數量,其中size()內部是調用了count(),所以size()和count()是一樣的。與length()的不同點是。。。。。。不知道怎麼描述,舉個例子
var cursor=db.student.find({age:20});

print(cursor.size());//結果20
print(cursor.length());//結果20

var s=cursor.next();
db.student.update(s,{$set:{name:"test"}});

print(cursor.size());//結果20
print(cursor.length());//結果20


var s=cursor.next();
db.student.update(s,{$set:{age:22}});

print(cursor.size());//結果19
print(cursor.length());//結果20
從例子可看出,當你更新的屬性與你查詢條件無關時length和size是一樣的,但當你更新的屬性是你的查詢條件時,即修改後該條記錄就不滿足你之前的查詢條件了,那麼size的結果就不包含該記錄,就是例子中最後的結果爲19。這兩個分別可以用於length初始滿足條件的條數,size用於update後還滿足條件的記錄條數。(有興趣的同學就去輸出cusrsor的這三個集合長度的方法看看分別的實現方式有什麼不同,這裏就不多講了,因爲shell是支持js的,cusrsor也是一個對象,所以輸出方式跟js的一樣)

(2)是否有下條記錄:s.hasNext(),true即表示有下一條
(3)遊標移到下一條記錄:s.next();
(4)遊標銷燬條件1、客戶端主動銷燬,2、遊標迭代完畢(即s.hasNest()爲false時,經測試直接輸出s和獲取s[s.size()]時也爲迭代完畢)。3、默認超過10分鐘沒有
(5)經測試在迭代完畢後確實使用p.hasNext()爲false,p.next()也獲取不到數據,但獲取長度和使用下標獲取數據是可以的即s.size().和s[i]是可以獲取到數據的,所以可以使用js進行for循環再次獲取對應的數據。但我不知道有沒有時間限制靠不靠譜。

7、數據內的數組及文檔查詢

有時候我們的某些字段是存一個數組或一個對象(這是比sql強的地方),那麼我們就需要對內部的值進行查詢,比如現在的student集合,我們需要查詢有java這本書的記錄,或要查詢數學成績爲90的記錄,對於數組內值的匹配有對應的$in,$nin,$not,$all,$size,$slice前面三個我們就不說了跟前面的應用差不多,$all操作符的意思是數組中包含所給條件的記錄,$size是查詢數組的長度等於條件的記錄,但他不支持小於大於操作,所以一般是以數組中第n個值存不存在來做小於大於的判斷,也可以使用上面提到的$where,進行判斷。$slice則是用於限定輸出,比如我只想看books的第0到1本書是什麼就可以使用這個。
例:
//查詢第一本書是java的記錄,注意這裏的books.1要用雙引號括起來
db.student.find({"books.1":"java"})

//查詢數組中包含java和mongodb的記錄
db.student.find({books:{$all:{"java","mongodb"}}})

//查詢數組中包含java或mongodb的記錄
db.student.find({books:{$in:[java","mongodb"]}})

//查詢數組長度爲4的記錄
db.student.find({books:{$size:4}})

//查詢數組長度小於3的記錄,index從0開始,所以books[2]不存在則長度小於3
db.student.find({ "books.2": {$exists:0} })

//查詢數組長度大於3的記錄,index從0開始,所以books[3]存在則長度大於3
db.student.find({ "books.3": {$exists:1} })

//使用$where查詢數組長度大於3的記錄
db.student.find({$where:"this.books!=null && this.books.length>3"})

//只查看前兩本書名
db.student.find({},{books:{$slice:[0,2]}})

//只查看最後一本書
db.student.find({},{books:{$slice:-1}})


查數組的對象,先來例子
//1、查詢數學成績80的,普通寫法
db.student.find({score:{name:"數學",score:80}})

//2、查詢有成績有80的,優化寫法
db.student.find({"score.score":80})

//3、查詢語文80的,錯誤寫法
 db.student.find({"score.name":"語文","score.score":80})

//4、查詢成績有80的,推薦寫法
db.student.find({score:{$elemMatch:{name:"語文",score:80}}})




第一條例子,普通寫法,這麼寫沒什麼問題,但是如果你要查詢成績中有80分的,那麼你就要進行一次或操作,數學80或語文80或英語80,科目越多,語句越長。所以複雜的對象不利使用。

所以有優化例子2,直接指明成績80分的,這裏需要注意的跟數組的下標一樣,score.score要用雙引號擴起來。

看到例子2,有人可能就會出現例子3,這種寫法了,其實這個語句是錯誤的,比如有兩條數據第一條是[{name:“語文”,score:90}],第二條[{name:“數學”,score:80}],根據例子3的寫法,mongodb會先拿第一個條件"score.name":"語文"跟第一條記錄匹配,爲正常,第二個條件"score.score":80不匹配,然後就會跳到第二條記錄,因爲"score.name":"語文"在第一條記錄時已匹配,所以到第二條時他直接驗證"score.score":80,匹配,那麼第二條記錄就會查詢出來了,但實際上這查詢結果是錯誤的。

正確的寫法是使用例子4,$elemMatch是對每個屬性的匹配,相當於例子1的簡寫,有人會說這是什麼簡寫,反而更長了,是的,在當前的例子中是更長了,但如果是條件多的話就會變得簡便了,比如有查詢語文或數學爲80的,只需加個in或or,即db.student.find({score:{$elemMatch:{name:{$in:["語文","數學"]},score:80}}})即可,對比第一個例子的寫法就需要or兩個對象,如果對象的屬性很多那就是個坑了。


8、分頁、排序

這個比較簡單,分頁跟mysql差不多,分頁利用限制條數limit(),和跳過條數skip()實現,排序則是使用sort(),1爲升序,-1爲降序。例:
//只查前2條
db.student.find().limit(2);

//查前3和4條
db.student.find().limit(2).skip(2);

//根據age升序排序
db.student.find().sort({age:1})
但實際上數據量比較大查詢比較頻繁時跳過條數mongodb不推薦使用skip,更推薦使用比較大小,比如按根據創建時間排序分頁,那麼直接查詢比上次查詢最後一條數據的創建時間小的數據即可。
還有一點mongodb跟js一樣對於對象是弱類型,即使age屬性,你也可以存整形,字符串、數組甚至null都可以,所以對於不同類型就有排序的優先級了,這裏不寫了,直接找個圖貼上來:

9、多表查詢


to be continued。。。。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章