1. 程式人生 > >MongoDB資料查詢,分頁,排序

MongoDB資料查詢,分頁,排序

MongoDB資料查詢

資料準備:persons.json

var persons = [{
    name:"jim",
    age:25,
    email:"75431457@qq.com",
    c:89,m:96,e:87,
    country:"USA",
    books:["JS","C++","EXTJS","MONGODB"]
},
{
    name:"tom",
    age:25,
    email:"214557457@qq.com",
    c:75,m:66,e:97,
    country:"USA",
    books:["PHP"
,"JAVA","EXTJS","C++"] }, { name:"lili", age:26, email:"344521457@qq.com", c:75,m:63,e:97, country:"USA", books:["JS","JAVA","C#","MONGODB"] }, { name:"zhangsan", age:27, email:"2145567457@qq.com", c:89,m:86,e:67, country:"China", books:["JS","JAVA","EXTJS"
,"MONGODB"] }, { name:"lisi", age:26, email:"274521457@qq.com", c:53,m:96,e:83, country:"China", books:["JS","C#","PHP","MONGODB"] }, { name:"wangwu", age:27, email:"65621457@qq.com", c:45,m:65,e:99, country:"China", books:["JS","JAVA","C++","MONGODB"] }, { name:"zhaoliu"
, age:27, email:"214521457@qq.com", c:99,m:96,e:97, country:"China", books:["JS","JAVA","EXTJS","PHP"] }, { name:"piaoyingjun", age:26, email:"piaoyingjun@uspcat.com", c:39,m:54,e:53, country:"Korea", books:["JS","C#","EXTJS","MONGODB"] }, { name:"lizhenxian", age:27, email:"lizhenxian@uspcat.com", c:35,m:56,e:47, country:"Korea", books:["JS","JAVA","EXTJS","MONGODB"] }, { name:"lixiaoli", age:21, email:"lixiaoli@uspcat.com", c:36,m:86,e:32, country:"Korea", books:["JS","JAVA","PHP","MONGODB"] }, { name:"zhangsuying", age:22, email:"zhangsuying@uspcat.com", c:45,m:63,e:77, country:"Korea", books:["JS","JAVA","C#","MONGODB"] }] for(var i = 0;i<persons.length;i++){ db.persons.insert(persons[i]) } var persons = db.persons.find({name:"jim"}) while(persons.hasNext()){ obj = persons.next(); print(obj.books.length) }
  1. 指定返回的鍵
    對於查詢,我們知道使用db.[collectionName].find()是返回全部資料,返回某個文件的全部鍵值,但是,某些時候我們會希望返回固定的鍵對應的值,那麼對於鍵指定,預設情況下,是會查詢出id,因此如果不想查詢出id或者某一列,新增id:0,這樣,此列不會被查詢出。
    語法:db.[collectionName].find({條件},{指定返回的鍵})
    例子:查詢出所有的資料指定的鍵(name,age,country)
db.persons.find({},{name:1,age:1,country:1,_id:0})

這裡寫圖片描述

  1. 查詢條件
    首先看一下比較操作符:
    例1:查詢出年齡在25到27歲之間的學生
db.persons.find({age:$gte:25,$lte:27}},_id:0,age:1,name:1})

這裡寫圖片描述
例2:查詢出所有不是韓國籍的學生的數學成績

db.persons.find({country:$ne:"Korea"}},name:1,_id:0,country:1})

這裡寫圖片描述
3. 包含或不包含
包含($in)和不包含($nin)類似關係型資料庫中的in和not in,該操作只能操作在陣列上。
例1:查詢國籍是中國或美國的學生資訊

 db.persons.find({country:{$in:["China","USA"]}},{name:1,_id:0,country:1})

這裡寫圖片描述
例2:查詢國籍不是中國或美國的學生資訊

 db.persons.find({country:{$nin:["China","USA"]}},{name:1,_id:0,country:1})

這裡寫圖片描述
4. OR查詢
or查詢即或者查詢,or查詢作用於陣列。
例:查詢語文成績大於85或者英語大於90的學生資訊

 db.persons.find({$or:[{c:{$gte:85}},{e:{$gte:90}}]},{_id:0,c:1,e:1,name:1})

這裡寫圖片描述

  1. Null
    首先資料修正:把中國國籍的學生上增加新的鍵ex,
    db.person.update({country:”China”},{$set:{sex:”m”}})
    這裡寫圖片描述
    例:查詢出sex 等於 null的學生
db.persons.find({sex:{$in:[null]}},{country:1,name:1,_id:0})

這裡寫圖片描述
6. 正則查詢
例:查詢出名字中存在”li”的學生的資訊

db.persons.find({name:/li/i},{_id:0,name:1})

這裡寫圖片描述
7. $not的查詢
$not可以用到任何地方進行取反操作。
例:查詢出名字中不存在”li”的學生的資訊

db.persons.find({name:{$not:/li/i}},{_id:0,name:1})

這裡寫圖片描述
8. 陣列查詢$all和index的應用
例:查詢喜歡看MONGOD和JS的學生

db.persons.find({books:{$all:["MONGODB","JS"]}},{books:1,_id:0})

這裡寫圖片描述
例:查詢第二本書是JAVA的學習資訊

db.persons.find({"books.1":"JAVA"},{_id:0,name:1,books:1})

這裡寫圖片描述

9 . 查詢指定長度陣列$size,它不能與比較查詢符一起使用(這是弊端)

例子:查詢出喜歡的書籍數量是4本的學生

db.persons.find({books:{$size:4}},{_id:0,books:1})

這裡寫圖片描述
例:查詢出喜歡的書籍數量大於3本的學生
這種情況下,由於size不能進行比較,則無法進行操作,解決方法可以修改文件結構,新增size鍵來記載書籍數量再進行比較查詢。

例:利用shell查詢出Jim喜歡看的書的數量

var persons = db.persons.find({name:"jim"})
while(persons.hasNext()){
    obj = persons.next();
        print(obj.books.length)
} 

10 . $slice操作符返回文件中指定陣列的內部值
例:查詢出Jim書架中第2~4本書

db.persons.find({name:"jim"},{books:{"$slice":[1,3]}})

這裡寫圖片描述
例:查詢出最後一本書

db.persons.find({name:"jim"},{books:{"$slice":-1},_id:0,name:1})

這裡寫圖片描述
11. 文件查詢
為jim新增學習簡歷文件 jim.json

var jim = [{
    school :"K",
    score:"A"
},{
    school :"L",
    score:"B"
},{
    school :"J",
    score:"A+"
}]
db.persons.update({name:"jim"},{$set:{school:jim}})

這裡寫圖片描述

例:查詢出在K上過學的學生
正常情況下,我們會進行如下查詢:

db.persons.find({school:{school:"K"}},{_id:0,school:1,name:1})

但是這種情況下無法查詢到資料:
這裡寫圖片描述
由於scholl是一個文件,所以我們應該使用文件匹配,如下:

db.persons.find({school:{school:"K",score:"A"}},{_id:0,school:1,name:1})

查詢結果如下:
這裡寫圖片描述
但是這種匹配方式,我們總要匹配Document中的全部資訊,比如我的查詢條件不需要score,但是依舊要寫,那麼來看下面的方式解決這個問題:

db.persons.find({"school.score":"A","school.school":"K"},{_id:0,school:1})

查詢結果:
這裡寫圖片描述

但是這種查詢,會出現如下問題:
查詢在J學校上課,成績為A的學生資訊:

db.persons.find({"school.score":"A","school.school":"J"},{_id:0,school:1})

這裡寫圖片描述

很明顯,該資料並不存在,但是依舊查詢出結果,因此此種方式有一定問題。
正確做法是使用單條條件組查詢$elemMatch

db.persons.find({school:{$elemMatch:{school:"K",score:"A"}}})

這裡寫圖片描述
而:

db.persons.find({"school.score":"A","school.school":"J"},{_id:0,school:1})

這裡寫圖片描述
12 . $where
複雜的查詢我們就可以用$where,因為$where是萬能,但是我們要儘量避免少使用它,因為使用$where會有效能的代價。
例:查詢年齡大於22歲,喜歡看C++書,在K學校上過學的學生資訊

db.persons.find({"$where":function(){
    //得到查詢結果的每一條文件
    var books = this.books;
    //得到文件中的school物件
    var school = this.school;
    //如果年紀>=22
    if(this.age > 22){
        var php = null;
        //遍歷書籍
        for ( var i = 0; i < books.length; i++) {
            if(books[i] == "C++"){
                php = books[i];
                //如果學校是真
                if(school){
                    for (var j = 0; j < school.length; j++) {
                        //判斷是不是在K上學
                        if(school[j].school == "K"){
                            //返回是真
                            return true;
                        }
                    }
                    break;
                }
            }
        }   
    }
}})

這裡寫圖片描述

MongoDB資料分頁

  1. limit和skip完成分頁
    limit類似於mysql中的limit,限制查詢條數
    skip為跨過多少條進行查詢。
    例:三條資料位一頁進行分頁
第一頁:db.persons.find({},{_id:0,name:1,books:1}).limit(3).skip(0)
第二頁:db.persons.find({},{_id:0,name:1,books:1}).limit(3).skip(3)
...

這裡寫圖片描述

  1. 其他分頁
    skip進行分頁會有效能問題,效率不高,沒有特殊要求的情況下,我們也可以換個思路進行分頁。
    如:我們可以對集合設計進行修正,給每個文件新增一個插入時間,若無特殊要求我們可以按照插入時間進行比較分頁。
db.persons.find({date:{$gt:日期數值}}).limit(3)

遊標

  1. 利用遊標遍歷查詢資料
    var  persons = db.persons.find();
    while(persons.hasNext()){
        obj = persons.next();
          print(obj.name)
     } 

這裡寫圖片描述
遊標查詢:
這裡寫圖片描述
遊標查詢是以此移動指標,當遊標移動到最後位置,則不能回到初始位置,因此遊標只能查詢一次,一次之後就不能查詢到資料。
2. 遊標的幾個銷燬條件
1). 客戶端發來資訊叫他銷燬
2). 遊標迭代完畢
3). 預設遊標超過10分鐘沒用也會被清除
3. 查詢快照
快照後就會針對不變的集合進行遊標運動了,看看使用方法.

    db.persons.find({$query:{name:"Jim"},$snapshot:true})
高階查詢選項
$query
$orderby
$maxsan:integer 最多掃描的文件數
$min:doc  查詢開始
$max:doc  查詢結束
$hint:doc   使用哪個索引
$explain:boolean  統計
$snapshot:boolean 一致快照 

4. .為什麼有的時候要用查詢快照?
因為有時候查詢之後,我們對資料進行了修改,如新增很大資料,超過了文件的預留記憶體,此時MongoDB會將大的文件移動到集合後面,則這種情況會導致查詢的資料有問題。如圖:
這裡寫圖片描述