当前位置: 首页 > 编程笔记 >

MongoDB中游标的深入学习

鲁华茂
2023-03-14
本文向大家介绍MongoDB中游标的深入学习,包括了MongoDB中游标的深入学习的使用技巧和注意事项,需要的朋友参考一下

前言

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的时候能带来一定的帮助,如果有疑问大家可以留言交流。

 类似资料:
  • 本文向大家介绍深入学习 Java 中的 Lambda,包括了深入学习 Java 中的 Lambda的使用技巧和注意事项,需要的朋友参考一下 前言 我花了相当多的阅读和编码时间才最终理解Java Lambdas如何在概念上正常工作的。我阅读的大多数教程和介绍都遵循自顶向下的方法,从用例开始,最后以概念性问题结束。在这篇文章中,我想提供一个自下而上的解释,从其他已建立的Java概念中推导出Lambda

  • 本文向大家介绍深入学习Java中的SPI机制,包括了深入学习Java中的SPI机制的使用技巧和注意事项,需要的朋友参考一下 概述 SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和Postgre

  • 本文向大家介绍深入学习JavaScript中的原型prototype,包括了深入学习JavaScript中的原型prototype的使用技巧和注意事项,需要的朋友参考一下 javascript 是一种 prototype based programming 的语言, 而与我们通常的 class based programming 有很大 的区别,我列举重要的几点如下: 1.函数是first cla

  • 本文向大家介绍深入学习Spring Cloud-Ribbon,包括了深入学习Spring Cloud-Ribbon的使用技巧和注意事项,需要的朋友参考一下 ribbon简介 Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的 软件负载均衡算法 ,将 Netflix 的中间层服务连接在一起。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文

  • 本文向大家介绍深入学习JavaScript对象,包括了深入学习JavaScript对象的使用技巧和注意事项,需要的朋友参考一下 JavaScript中,除了五种原始类型(即数字,字符串,布尔值,null,undefined)之外的都是对象了,所以,不把对象学明白怎么继续往下学习呢? 一.概述 对象是一种复合值,它将很多值(原始值或其他对象)聚合在一起,可通过属性名访问这些值。而属性名可以是包含空字

  • 本文向大家介绍深入学习Bootstrap表单,包括了深入学习Bootstrap表单的使用技巧和注意事项,需要的朋友参考一下 本文知识点借鉴来自http://www.runoob.com/bootstrap/bootstrap-forms.html,里面写的比较详细还给出了例子,这里总结一下重点方便记忆。 一、表单布局 1.垂直表单(默认)         向父 <form> 元素添加 role="