第12章:MongoDB-CRUD操做--文檔--查詢--遊標詳解

①是什麼遊標

遊標不是查詢結果,能夠理解爲數據在遍歷過程當中的內部指針,其返回的是一個資源,或者說數據讀取接口.web

客戶端經過對遊標進行一些設置就能對查詢結果進行有效地控制,如能夠限制查詢獲得的結果數量、跳過部分結果、或對結果集按任意鍵進行排序等!shell

直接對一個集合調用find()方法時,咱們會發現,若是查詢結果超過二十條,只會返回二十條的結果,這是由於Mongodb會自動遞歸find() 返回的遊標。數據庫

②mongoDB遊標介紹

db.collection.find()方法返回一個遊標,對於文檔的訪問,咱們須要進行遊標迭代mongoDB的遊標與關係型數據庫SQL中的遊標相似,能夠經過對遊標進行(如限制查詢結果數,跳過的結果數等)設置來控制查詢結果json

遊標會消耗內存和相關係統資源,遊標使用完後應儘快釋放資源數組

在mongo shell中,若是返回的遊標結果集未指定給某個var定義的變量,則遊標自動迭代20次,即輸出前20個文檔,超出20的情形則須要輸入it來翻頁服務器

本文內容描述手動方式來實現遊標迭代來訪問文檔或者是用索引迭代spa

 

 

聲明遊標.net

   var cursor = db.collectioName.find(query,projection);指針

 

 

打開遊標code

   Cursor.hasNext() 判斷遊標是否已經取到盡頭

 

 

讀取數據

   Cursor.Next()  取出遊標的下一個文檔

 

 

關閉遊標

   cursor.close()  此步驟可省略,一般爲自動關閉,也能夠顯示關閉

 

 

用while循環來遍歷遊標示例

   var mycursor = db.bar.find({_id:{$lte:5}})

   while(mycursor.hasNext()) {

       printjson(mycursor.next());

       }

 

 

遊標生命週期

   a、遊標完成匹配結果的迭代後,它會清除自身;

   b、客戶端的遊標已經不在做用域內,驅動程序迴向服務器發送一條特別的消息,讓其銷燬;

   c、缺省狀況下,遊標在十分鐘內沒有使用,遊標自動關閉或者客戶端已經迭代完整個遊標;

   d、能夠經過cursor.noCursorTimeout()來定義遊標超時時間

       如:var myCursor = db.users.find().noCursorTimeout()

   e、對於自定義超時時長的遊標可使用cursor.close() 來關閉遊標

       如:db.collection.find(<query>).close()

③當前環境及數據準備

repSetTest:PRIMARY> db.version();

3.0.12

//建立包含29個文檔的集合user

repSetTest:PRIMARY> for (var i=1;i<30;i++){

... db.user.insert({"id":i,"ename":"usr"+i});

... }

WriteResult({ "nInserted" : 1 })

repSetTest:PRIMARY> db.user.count()

29

 

//查詢集合user上全部文檔

repSetTest:PRIMARY> db.user.find()

{ "_id" : ObjectId("5804d07fd974b32430ea9748"), "id" : 1, "ename" : "usr1" }

{ "_id" : ObjectId("5804d07fd974b32430ea9749"), "id" : 2, "ename" : "usr2" }

      .............................

{ "_id" : ObjectId("5804d07fd974b32430ea975b"), "id" : 20, "ename" : "usr20" }

Type "it" for more  //上面的結果只輸出了20行,這個提示代表查看更多應輸入it

 

repSetTest:PRIMARY> it

{ "_id" : ObjectId("5804d07fd974b32430ea975c"), "id" : 21, "ename" : "usr21" }

 ..............

{ "_id" : ObjectId("5804d07fd974b32430ea9764"), "id" : 29, "ename" : "usr29" }

④使用print輸出遊標結果集

repSetTest:PRIMARY> var myCursor = db.user.find();

                    while (myCursor.hasNext()) {

                             print(tojson(myCursor.next()))

                    }

 

 

{ "_id" : ObjectId("5804d07fd974b32430ea9748"), "id" : 1, "ename" : "usr1" }

   ..........

{

    "_id" : ObjectId("5804d07fd974b32430ea9751"),

    "id" : 10,

    "ename" : "usr10"

}

   ................

{

    "_id" : ObjectId("5804d07fd974b32430ea9764"),

    "id" : 29,

    "ename" : "usr29"

}

//上述查詢中經過var myCursor進行變量的定義,至關於SQL中的declare cursor cur_name is select ..

//變量 myCursor定義僅僅是定義,並不會訪問數據庫,而是在myCursor.hasNext()真正訪問數據庫

//myCursor.next()則是輸出下一條記錄,hasNext()訪問數據庫時會根據缺省遊標設定將結果讀取到本地

⑤使用printjsont輸出遊標結果集

repSetTest:PRIMARY> var myCursor = db.user.find({id:{$gt:20}});

                    while (myCursor.hasNext()) {

                              printjson(myCursor.next());

                    }

 

{

   "_id" : ObjectId("5804d07fd974b32430ea975c"),

   "id" : 21,

   "ename" : "usr21"

}

    .......

{

   "_id" : ObjectId("5804d07fd974b32430ea9764"),

   "id" : 29,

   "ename" : "usr29"

}

⑥使用forEach()進行迭代

repSetTest:PRIMARY> var myCursor = db.user.find({id:{$gt:20}})

repSetTest:PRIMARY> myCursor.forEach(printjson);

{

   "_id" : ObjectId("5804d07fd974b32430ea975c"),

   "id" : 21,

   "ename" : "usr21"

}

   ................

{

   "_id" : ObjectId("5804d07fd974b32430ea9764"),

   "id" : 29,

   "ename" : "usr29"

}

⑦基於數組索引迭代

 

可使用toArray()將遊標迭代文檔返回到一個數組,而後經過數組下標方式進行訪問。該方法將全部由遊標返回的文檔裝載進內存。

 

 

以下示例,將遊標返回的內容傳遞到數組,而後使用 printjson (documentArray[3])輸出其中的元素

repSetTest:PRIMARY> var myCursor = db.user.find({id:{$gt:20}})

repSetTest:PRIMARY> var documentArray = myCursor.toArray();

repSetTest:PRIMARY> printjson (documentArray[3])

{

    "_id" : ObjectId("580d775edeb57e4d05eec0f2"),

    "id" : 24,     //Author : Leshami

    "ename" : "usr24" //Blog  : http://blog.csdn.net/leshami

}

 

//也能夠將數組元素輸出到某個變量,而後在用printjson(myDocument)輸出這個變量,以下

repSetTest:PRIMARY> var myDocument = documentArray[3];

repSetTest:PRIMARY> printjson(myDocument)

{

    "_id" : ObjectId("580d775edeb57e4d05eec0f2"),

    "id" : 24,

    "ename" : "usr24"

}

⑧調整遊標迭代次數

//設置迭代顯示的次數,以下設置爲5

repSetTest:PRIMARY> DBQuery.shellBatchSize = 5

5

repSetTest:PRIMARY> db.user.find()

{ "_id" : ObjectId("5804d07fd974b32430ea9748"), "id" : 1, "ename" : "usr1" }

{ "_id" : ObjectId("5804d07fd974b32430ea9749"), "id" : 2, "ename" : "usr2" }

{ "_id" : ObjectId("5804d07fd974b32430ea974a"), "id" : 3, "ename" : "usr3" }

{ "_id" : ObjectId("5804d07fd974b32430ea974b"), "id" : 4, "ename" : "usr4" }

{ "_id" : ObjectId("5804d07fd974b32430ea974c"), "id" : 5, "ename" : "usr5" }

Type "it" for more //從上面的查詢結果可知,當輸出5個文檔就提示須要輸入it來查看更多

repSetTest:PRIMARY> it

{ "_id" : ObjectId("5804d07fd974b32430ea974d"), "id" : 6, "ename" : "usr6" }

{ "_id" : ObjectId("5804d07fd974b32430ea974e"), "id" : 7, "ename" : "usr7" }

{ "_id" : ObjectId("5804d07fd974b32430ea974f"), "id" : 8, "ename" : "usr8" }

{ "_id" : ObjectId("5804d07fd974b32430ea9750"), "id" : 9, "ename" : "usr9" }

{ "_id" : ObjectId("5804d07fd974b32430ea9751"), "id" : 10, "ename" : "usr10" }

Type "it" for more

 

⑨查看遊標度量信息

能夠經過db.serverStatus()查看遊標狀態相關的信息,這些信息一般包括

    從服務器上次啓動以後遊標超時的數量

    自定義遊標超時的數量

    遊標打開後已經pinned的數量

    打開遊標的總數目

//以下查詢本機遊標的信息    

repSetTest:PRIMARY> db.serverStatus().metrics.cursor

{

    "timedOut" : NumberLong(2),

    "open" : {

        "noTimeout" : NumberLong(0),

        "pinned" : NumberLong(0),

        "total" : NumberLong(2)

    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章
相關標籤/搜索