前言
MongoDB中的游標與關系型數據庫中的游標在功能上大同小異。游標相當於C語言的指針,可以定位到某條記錄,在MongoDB中,則是文檔。因此在mongoDB中游標也有定義,聲明, 打開,讀取,關閉這麼個過程。客戶端通過游標,能夠實現對最終結果進行有效的控制,諸如限制結果數量,跳過部分結果或根據任意鍵按任意順序的組合對結果進行各種排序等。
通俗的說,游標不是查詢結果,可以理解為數據在遍歷過程中的內部指針,其返回的是一個資源,或者說數據讀取接口.
客戶端通過對游標進行一些設置就能對查詢結果進行有效地控制,如可以限制查詢得到的結果數量、跳過部分結果、或對結果集按任意鍵進行排序等!
直接對一個集合調用find()方法時,我們會發現,如果查詢結果超過二十條,只會返回二十條的結果,這是因為Mongodb會自動遞歸find() 返回的游標。
下文是針對MongoDB游標的具體介紹。
一、mongoDB游標介紹
db.collection.find()
方法返回一個游標,對於文檔的訪問,我們需要進行游標迭代
mongoDB的游標與關系型數據庫SQL中的游標類似,可以通過對游標進行(如限制查詢結果數,跳過的結果數等)設置來控制查詢結果
游標會消耗內存和相關系統資源,游標使用完後應盡快釋放資源
在mongo shell中,如果返回的游標結果集未指定給某個var定義的變量,則,游標自動迭代20次,即輸出前20個文檔,超出20的情形則需要輸入it來翻頁
本文內容描述手動方式來實現游標迭代來訪問文檔或者是用索引迭代
聲明游標
var cursor = db.collectioName.find(query,projection);
打開游標
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) } }
總結
以上就是關於MongoDB游標的全部內容了,希望本文的內容對大家學習或者使用MongoDB的時候能帶來一定的幫助,如果有疑問大家可以留言交流。