【MongoDB】MongoDB查询语句find的使用,和提高查询速度的游标的使用,非常详细!!!

在这里插入图片描述

😁 作者简介:一名大四的学生,致力学习前端开发技术
⭐️个人主页:夜宵饽饽的主页
❔ 系列专栏:MongoDB数据库
👐学习格言:成功不是终点,失败也并非末日,最重要的是继续前进的勇气

​🔥​前言:

这里是关于MongoDB中查询语句find的使用,其中对于特定类型的查询非常特别,还有游标的使用可以加快我们的查询速度,这是我的学习MongoDB笔记,希望可以帮助到大家,欢迎大家的补充和纠正

文章目录

  • 第4章 查询
    • 4.1 find简介
      • 4.1.1 指定要返回的键
    • 4.3 特定类型查询
      • 4.3.3 查询数组之$slice操作符
      • 4.3.5 查询数组之数组与范围查询的相互作用
    • 4.4 $where查询
    • 4.5 游标
      • 4.5.1 limit,skip和sort
      • 4.5.2 避免略过大量结果
      • 4.5.3 游标生命周期

第4章 查询

4.1 find简介

4.1.1 指定要返回的键

概念:find方法中的第二个参数就是投影条件,投影条件是一个文档,其中键是要包含或排除的字段,对应的值为 1 表示包含,0 表示排除。默认情况下,如果不指定投影条件,MongoDB 会返回文档中的所有字段
案例:

  1. 默认情况下,如果不指定投影条件,MongoDB 会返回文档中的所有字段
> db.users.find({}, {"username" : 1, "email" : 1})
{
    "_id" : ObjectId("4ba0f0dfd22aa494fd523620"),
    "username" : "joe",
    "email" : "joe@example.com"
}

2.可能在文档中有很多键,而你不希望结果中包含 “fatal_weakness” 键:

> db.users.find({}, {"fatal_weakness" : 0})

3.要将“_id“键从返回结果剔除

> db.users.find({}, {"username" : 1, "_id" : 0})
{
    "username" : "joe"
}

4.3 特定类型查询

4.3.3 查询数组之$slice操作符

注意点:除非特别指定,否则在使用 “$slice” 时会返回文档中的所有键。这与其他的键指定符不同,后者不会返回未指定的键。例如,有这样一个关于博客文章的文档:
例子:

{
    "_id" : ObjectId("4b2d75476cc613d5ee930164"),
    "title" : "A blog post",
    "content" : "...",
    "comments" : [
        {
            "name" : "joe",
            "email" : "joe@example.com",
            "content" : "nice post."
        },
        {
            "name" : "bob",
            "email" : "bob@example.com",
            "content" : "good post."
        }
    ]
}

> db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -1}})
{
    "_id" : ObjectId("4b2d75476cc613d5ee930164"),
    "title" : "A blog post",
    "content" : "...",
    "comments" : [
        {
            "name" : "bob",
            "email" : "bob@example.com",
            "content" : "good post."
        }
    ]
}

即使title和content没有显式地被包含在键指定符中,但它们依然被返回了

4.3.5 查询数组之数组与范围查询的相互作用

文档中的标量(非数组元素)必须与查询条件中的每一条子句相匹配。如果使用 {“x” : {“ g t " : 10 , " gt" : 10, " gt":10,"lt” : 20}} 进行查询,那么 “x” 必须同时满足大于 10 且小于 20。然而,如果文档中的 “x” 字段是一个数组,那么当 “x” 键的某一个元素与查询条件的任意一条语句相匹配(查询条件中的每条语句可以匹配不同的数组元素)时,此文档也会被返回。
接下来我们可以来看一个例子:
现在有一个文档

{"x" : 5}
{"x" : 15}
{"x" : 25}
{"x" : [5, 25]}

如果想找出 “x” 的值在 10 和 20 之间的所有文档,那么你可能会本能地构建这样的查询,即 db.test.find({“x” : {“ g t " : 10 , " gt" : 10, " gt":10,"lt” : 20}}),然后期望它会返回一个文档:{“x” : 15}。然而,当实际运行时,我们得到了两个文档,如下所示:

> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}})
{"x" : 15}
{"x" : [5, 25]}

5 和 25 都不在 10 和 20 之间,但由于 25 与查询条件中的第一个子句("x"的值大于 10)相匹配,5 与查询条件中的第二个子句(“x” 的值小于 20)相匹配,因此这个文档会被返回。
😐 这样就使得针对数组的范围查询基本失去了作用:一个范围会匹配任何多元素数组,有几种方法可以获得预期的行为
1.可以使用 e l e m M a t h 强制 M o n g o D B 将这两个子句与单个数组元素进行比较,不过 elemMath强制MongoDB将这两个子句与单个数组元素进行比较,不过 elemMath强制MongoDB将这两个子句与单个数组元素进行比较,不过elemMath不会匹配非数组元素

> db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}}})
> // 没有结果

文档 {“x” : 15} 不再与查询条件匹配了,因为它的 “x” 字段不是一个数组。也就是说,你应该有充分的理由在一个字段中混合数组和标量值,而这在很多场景中并不需要。对于这样的情况,“ e l e m M a t c h " 为数组元素的范围查询提供了一个很好的解决方案。 ∗ ∗ 2. 如果在要查询的字段上有索引(参见第 5 章),那么可以使用 m i n 和 m a x 将查询条件遍历的索引范围限制为 " elemMatch" 为数组元素的范围查询提供了一个很好的解决方案。 **2.如果在要查询的字段上有索引(参见第 5 章),那么可以使用 min 和 max 将查询条件遍历的索引范围限制为 " elemMatch"为数组元素的范围查询提供了一个很好的解决方案。2.如果在要查询的字段上有索引(参见第5章),那么可以使用minmax将查询条件遍历的索引范围限制为"gt” 和 “$lt” 的值**

> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}}).min({"x" : 10}).max({"x" : 20})
{"x" : 15}

现在,这条查询语句只会遍历值在 10 和 20 之间的索引,不会与值为 5 和 25的这两个条目进行比较。但是,只有在要查询的字段上存在索引时,才能使用min 和 max,并且必须将索引的所有字段传递给 min 和 max
🍁在查询可能包含数组的文档的范围时,使用 min 和 max 通常是一个好主意。在整个索引范围内对数组使用 “ g t " / " gt"/" gt"/"lt” 进行查询是非常低效的。它基本上接受任何值,因此会搜索每个索引项,而不仅仅是索引范围内的值。

4.4 $where查询

概念: 允许你在查询中执行任意的 JavaScript 代码

例子:

> db.foo.find({"$where" : function () {
... for (var current in this) {
...     for (var other in this) {
...         if (current != other && this[current] == this[other]) {
...             return true;
...         }
...     }
... }
... return false;
... }});

注意:除非绝对必要,否则不应该使用 “$where” 查询:它们比常规查询慢得多

4.5 游标

概念:游标(Cursor)是用于遍历查询结果的对象,你执行查询时,MongoDB 返回一个游标,它指向查询结果的初始位置。通过游标,你可以逐步获取结果集中的文档,而不需要一次性将整个结果集加载到内存中。
案例:

> for(i=0; i<100; i++) {
...     db.collection.insertOne({x : i});
... }
> var cursor = db.collection.find();

> while (cursor.hasNext()) {
...     obj = cursor.next();
...     // 执行任务
... }

//还有一种用法,游标cursor类还实现了Js的迭代器接口,因此可以使用forEach
> var cursor = db.people.find();
> cursor.forEach(function(x) {
...     print(x.name);
... });
adam
matt
zak

上述案例中,find方法就返回一个游标,cursor.hasNext() 会检查是否有后续结果存在,而 cursor.next() 用来对其进行获取。
游标的工作机制:

  1. **查询请求:**当客户端发起一个查询请求,MongoDB服务器接受请求
  2. 返回游标:服务器会返回一个包含初始查询结果的游标给客户端,这是,并不会立刻返回所有匹配的文档,而是返回一个包含部分结果的游标对象,这个部分结果一般来说是100个结果或者4MB的数据(两者中较小者)
  3. 分批获取:客户端可以使用游标的方法(如next)来逐批获取文档。当客户端请求下一批文档时,服务器会在需要时继续执行查询,获取更多的文档,并返回给客户端。
  4. **游标生命周期:**获取的过程会一直持续,知道游标耗尽或者结果被全部返回

4.5.1 limit,skip和sort

  1. limit:会限制返回结果的数量,传入的参数只能是正数,负数会报错
  2. skip:会跳过指定数量的文档,然后返回剩下的文档,参数也是正数
  3. sort:会接受一个对象作为参数,这个对象是一组键–值对,键对应文档的键名,值对应排序的方向。排序方向可以是 1(升序)或 -1(降序)。如果指定了多个键,则结果会按照这些键被指定的顺序进行排序。例如,要按照 “username” 升序及 “age” 降序排列

案例:实现分页,假设你正在运营一个在线商店,有人想搜索 mp3。如果想每页返回 50 个结果并按照价格从高到低排序

> db.stock.find({"desc" : "mp3"}).limit(50).sort({"price" : -1})

//如果顾客单机下一页
> db.stock.find({"desc" : "mp3"}).limit(50).skip(50).sort({"price" : -1})

然而,略过大量的结果会导致性能问题
比较顺序
MongoDB 对于类型的比较有一个层次结构。有时一个键的值可能有多种类型:整型和布尔型,或者字符串和 null。如果对混合类型的键进行排序,那么会有一个预定义的排序顺序。从最小值到最大值,顺序如下。

  • 最小值
  • null
  • 数字(整型、长整型、双精度浮点型、小数型)
  • 字符串
  • 对象/文档
  • 数组
  • 二进制数据
  • 对象 ID
  • 布尔型
  • 日期
  • 时间戳
  • 正则表达式
  • 最大值

4.5.2 避免略过大量结果

使用 skip 来略过少量的文档是可以的。但对于结果非常多的情况,skip 会非常慢,因为需要先找到被略过的结果,然后再丢弃这些数据。大多数数据库会在索引中保存更多的元数据以处理 skip,但 MongoDB 目前还不支持这样做,所以应该避免略过大量的数据
1.不使用skip对结果进行分页
最简单的方式就是使用limit和skip互相配合,用偏移量来进行返回:

> // 不要这么做:略过大量数据会非常慢
> var page1 = db.foo.find(criteria).limit(100)
> var page2 = db.foo.find(criteria).skip(100).limit(100)
> var page3 = db.foo.find(criteria).skip(200).limit(100)
...

使用skip查询很多结果时,会非常慢,所以我们有一种不使用skip来进行分页的方法,就是使用排序和条件查询
假设要按照date**降序显式文档,**可以使用以下方式获取第一页:

> var page1 = db.foo.find().sort({"date" : -1}).limit(100)

然后,假设日期是唯一的,可以使用最后一个文档的 “date” 值作为获取下一页的查询条件:

var latest = null;

// 显示第1页
while (page1.hasNext()) {
    latest = page1.next();
    display(latest);
}

// 获取下一页
var page2 = db.foo.find({"date" : {"$lt" : latest.date}});
page2.sort({"date" : -1}).limit(100);

2.查询一个随机文档
我们首先也会翻译使用skip来随机跳过数据来获取

> // 不要这样做
> var total = db.foo.count()
> var random = Math.floor(Math.random()*total)
> db.foo.find().skip(random).limit(1)

以这种方式获取随机元素实际上非常低效:必须先计算总数(如果使用查询条件,这会是一个昂贵的操作),并且略过大量的元素也会非常耗时
我们还有一种比较好的方法,不过需要提前计划,在文档中设置random键

> db.people.insertOne({"name" : "joe", "random" : Math.random()})
> db.people.insertOne({"name" : "john", "random" : Math.random()})
> db.people.insertOne({"name" : "jim", "random" : Math.random()})

这样,我们就可以使用正常的条件查询来查询,而不用使用skip

> var random = Math.random()
> result = db.people.findOne({"random" : {"$gt" : random}})

random 可能会大于集合中的任何 “random” 值,并且不会返回任何结果。可以简单地从另一个方向返回文档以避免这种情况:

> if (result == null) {
...     result = db.people.findOne({"random" : {"$lte" : random}})
... }

如果集合中没有任何文档,那么这种方式会返回 null,这也是合理的。

4.5.3 游标生命周期

在服务器,游标会占用内存和资源,所以我们需要释放游标,有以下几种情况会释放游标

  • 当游标遍历完结果之后,它会清除自身
  • 当游标超出客户端的作用域,驱动程序会向数据库发送一条特殊的消息,让数据库知道它可以“杀死”该游标
  • 用户没有遍历完所有结果而且游标仍在作用域内,如果 10 分钟没有被使用的话,数据库游标也将自动“销毁”。

有时候,我们需要一个游标维持很长时间,这种情况下,我们应该怎么办呢?
许多驱动程序实现了一个称为 immortal 的函数,或者类似的机制,它告诉数据库不要让游标超时。
如果关闭了游标超时,则必须遍历完所有结果或主动将其销毁以确保游标被关闭。否则,它会一直占用数据库的资源,直到服务器重新启动

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/298168.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL基础篇(三)约束

一、概述 概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 目的&#xff1a;保证数据库中数据的正确、有效性和完整性。 分类&#xff1a; 注意&#xff1a;约束是作用于表中字段上的&#xff0c;可以在创建表/修改表的时候添加约束。 二…

Java BIO、NIO、AIO、Netty知识详解(值得珍藏)

1. 什么是IO Java中I/O是以流为基础进行数据的输入输出的&#xff0c;所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。简单来说就是java通过io流方式和外部设备进行交互。 在Java类库中&#xff0c;IO部分的内容是很庞大的&#xff0c;因为它涉及的领…

【每日一题】在链表中插入最大公约数

文章目录 Tag题目来源解题思路方法一&#xff1a;迭代 写在最后 Tag 【迭代】【辗转相除法】【链表】【2024-01-06】 题目来源 2807. 在链表中插入最大公约数 解题思路 方法一&#xff1a;迭代 思路 首先需要求两个数的最大公约数&#xff0c;使用辗转相除法。实现代码如下…

PyQT 多进程

在PyQt中&#xff0c;图形化界面&#xff08;GUI&#xff09;是运行在主线程中的&#xff0c;而多进程是在独立的进程中执行的。默认情况下&#xff0c;多进程之间是无法直接共享图形化界面的。 然而&#xff0c;有几种方法可以在多进程中与PyQt的图形化界面进行通信&#xff…

【大数据】Zookeeper 客户端的命令行操作

Zookeeper 客户端的命令行操作 1.显示某个路径下的所有节点&#xff1a;ls2.显示某个路径下的所有节点&#xff0c;以及当前节点的详细信息&#xff1a;ls23.创建节点&#xff1a;create4.创建临时节点&#xff1a;create -e5.创建顺序&#xff08;带编号&#xff09;节点&…

程序员副业之无人直播助眠

介绍和概览 大家好&#xff0c;我是小黑&#xff0c;本文给大家介绍一个比较轻松简单的副业&#xff0c;无人直播助眠副业。 这个项目的核心就是通过直播一些助眠素材来赚钱。比如你可以放一些舒缓的雨声之类的&#xff0c;吸引观众进来。然后&#xff0c;咱们可以挂个小程序…

DS|哈希查找

题目一&#xff1a;DS哈希查找 -- 线性探测再散列 题目描述&#xff1a; 定义哈希函数为H(key) key%11&#xff0c;输入表长&#xff08;大于、等于11&#xff09;。输入关键字集合&#xff0c;用线性探测再散列构建哈希表&#xff0c;并查找给定关键字。 输入要求&#xf…

【C语言】Linux实现高并发处理的过程

一、实现高并发的几种策略 C语言本身并没有内建的多线程支持&#xff08;新版C语言支持&#xff0c;但用得不多&#xff09;&#xff0c;但是在多数操作系统中&#xff0c;可以使用库来实现多线程编程。例如&#xff0c;在POSIX兼容系统上&#xff0c;可以使用 pthreads 库来创…

如何建立标准且有效的评审流程?6个重点

为了进一步提高项目质量&#xff0c;项目评审管理需要遵循一定的标准化流程。而建立标准且有效的评审流程&#xff0c;能够快速提高项目质量和效率&#xff0c;优化团队协作&#xff0c;降低风险&#xff0c;提高项目成功率。如果组织没有建立起标准化的评审流程&#xff0c;就…

JAVAEE初阶相关内容第二十弹--HTTP协议【续集】

写在前&#xff1a;在前一篇博客中我们初步掌握了HTTP(超文本传输协议)的相关知识【点击跳转】&#xff0c;认识了HYYP协议的工作过程&#xff0c;掌握抓包工具Fiddler的使用。在“方法”中重点需要理解“GET”方法与“POST”方法的格式与内容&#xff0c;并了解了请求“报头”…

万众期盼的剪辑新功能来了 会声会影2024旗舰版焕新登场

会声会影2024全新升级来袭&#xff0c;Corel公司这次为用户带来了多项功能更新&#xff0c;软件风格整体更偏向于“轻松剪辑&#xff0c;快速出片”。会声会影的本次更新还是很令人惊喜的&#xff0c;在各种人工智能算法的加持下&#xff0c;用户只需要进行几步简单地设置&…

sublim安装Autoprefixer插件

有时候在写css样式的时候&#xff0c;分不清哪些属性需要前缀&#xff0c;哪些不需要写前缀&#xff0c;sublime text这款编辑器下安装autoprefixer这款插件可以省去很多问题&#xff0c;写起来也很方便。1 确保系统已经安装node.js 可直接去官网上下载并安装&#xff0c;我的系…

网络实训模拟考察题目和答案(华为eNSP综合实验考试)

拓扑中四个交换机五个路由器&#xff0c;共九个设备 答案是对应的九个脚本&#xff08;从设备命名到保存&#xff09; 全部复制粘贴后&#xff0c;从PC1、PC2都是能Ping通服务器的&#xff08;保及格&#xff09;&#xff0c;其他要求没检查 题目 VLAN信息 设备名称端口链路…

【设计模式之美】面向对象分析方法论与实现(一):需求分析方法论

文章目录 一. 需求举例二. 对案例进行需求分析1. 第一轮基础分析2. 第二轮分析优化3. 第三轮分析优化4. 第四轮分析优化5. 最终确定需求 三. 小结 本文主要描述&#xff1a; 面向对象的需求分析方法论 一. 需求举例 假设&#xff0c;你正在参与开发一个微服务。微服务通过 HTT…

软件测试|SQL JOIN的用法,你会了吗?

SQL JOIN 是在关系型数据库中常用的操作&#xff0c;用于将两个或多个表中的数据合并起来&#xff0c;以满足查询需求。本文将介绍 SQL JOIN 的基本概念、不同类型的 JOIN&#xff0c;以及使用示例。 SQL JOIN 的概念 在关系型数据库中&#xff0c;数据通常分布在多个表中&am…

【C语言】关闭socket需要包含的头文件

一、问题 linux系统&#xff0c;包含了头文件<sys/socket.h>&#xff0c; 警告 warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration] close(sockclient); ^~~~~ pclose 二、解决 在 Linux 系统下…

网络安全是什么?一文认识网络安全

一、网络安全 1.概念 网络安全从其本质上讲就是网络上的信息安全&#xff0c;指网络系统的硬件、软件及数据受到保护。不遭受破坏、更改、泄露&#xff0c;系统可靠正常地运行&#xff0c;网络服务不中断。 &#xff08;1&#xff09;基本特征 网络安全根据其本质的界定&#…

labview 与三菱FX 小型PLC通信(OPC)

NI OPC服务器与三菱FX3U PLC通讯方法 一、新建通道名称为&#xff1a;MIT 二、选择三菱FX系列 三、确认端口号相关的参数&#xff08;COM端&#xff1a;7.波特率&#xff1a;9600&#xff0c;数据位&#xff1a;7&#xff0c;校验&#xff1a;奇校验&#xff0c;停止位&#xf…

码农的周末日常---2024/1/6

上周总结 按照规划进行开发&#xff0c;处事不惊&#xff0c;稳稳前行 2024.1.6 天气晴 温度适宜 AM 睡觉前不建议做决定是真的&#xff0c;昨天想着睡到中午&#xff0c;今天九点多醒了&#xff0c;得了&#xff0c;不想睡了 日常三连吧&#xff0c;…

面试官:String为什么要设计为不可变类

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …