MongoDB——查询操作详解

查询语法
db.collection_name.find
(
	query, //查询条件
	projection //可选,指定需要返回的字段;默认返回所有字段
)
查询集合所有文档

在这里插入图片描述

可以在find()后调用pretty()方法将返回结果美化显示:

在这里插入图片描述

等价条件查询

公共查询条件:{<key1>:<value1>, <key2>:<value2>,...},多条件时进行与(and)条件查询。

在这里插入图片描述
在这里插入图片描述

若不想显示_id字段,可以进行如下操作:
在这里插入图片描述
0或false表示不显示指定字段,1或true显示指定字段。

嵌套文档查询

有两种方式可以查询内嵌文档:查询整个文档,或者只针对其键值对进行查询。

查询整个内嵌文档与普通查询完全相同。

在这里插入图片描述
要查询Joe Schmoe:
在这里插入图片描述
如果要查询一个完整的子文档,那么子文档必须精确匹配。如果Joe决定添加一个代表中间名的键,这个查询就不再可行了。而且这种查询还是与顺序相关的,调换顺序什么都匹配不到:
在这里插入图片描述

只针对内嵌文档的特定键值查询可以使用点表示法,这样即使数据模式改变,也不会因为要精准匹配而导致挂掉:
在这里插入图片描述

假如:有博客文章若干,要找到由Joe发表的5分以上的评论。博客文章如下:
在这里插入图片描述
不能直接用db.blog.find({comments:{author:"joe", score:{$gte:5}}})来查询:
在这里插入图片描述
内嵌文档的匹配,必须要整个文档完全匹配,而这个查询不会匹配comment键。使用``db.blog.find({“comments.author”:“joe”, “comments.score”:{$gte:5}})`也不行,因为符合author条件的评论和符合score条件的评论可能不是同一条评论。也就是说,会返回刚才显示的那个文档。因为author:"joe"在第一条评论中匹配了,score:6在第二条评论中匹配了:
在这里插入图片描述

要正确指定一组条件,而不必指定每个键,就需要使用$elemMatch
在这里插入图片描述

数组查询

插入一个数组:
在这里插入图片描述

等价查询数组:
在这里插入图片描述
查询包含某一个值的数组:
在这里插入图片描述

查询指定位置的数组,需要使用key.index指定下标:
在这里插入图片描述

查询包含多个值的数组(顺序无关):
在这里插入图片描述

查询指定长度的数组:
在这里插入图片描述

查找null值字段

在这里插入图片描述
null不仅会匹配某个键的值为null的文档,而且还会匹配不包含这个键的文档。所以,这种匹配还会返回去烧这个键的所有文档。

如果仅仅想匹配键值为null的文档,既要检查该建的值是否为null,还要通过"$exists"条件判定键是否存在。

在这里插入图片描述

查找指定无值字段

在这里插入图片描述

查找返回值游标操作

在这里插入图片描述

$slice操作符

$slice操作符可以返回某个键匹配的数组元素的一个子集

返回前3条:
在这里插入图片描述
返回后3条:
在这里插入图片描述

返回中间的部分:跳过前2条,返回第3条
在这里插入图片描述
注意:除非指定返回键,否则$slice默认返回文档中的所有键。

数组和范围查询的相互作用

文档中的标量(非数组元素)必须与查询条件中的每一条语句相匹配。
例如,如果使用{"x":{"$gt":10, "$lt":20}}进行查询,只会匹配x键的值大于等于10且夏鸥等于20的文档。但是,加入某个文档的x字段是一个数组,如果x键的某一个元素与查询条件的任意一掉语句相匹配(查询条件中的每条语句可以匹配不同的数组元素),那么这个文档也会被返回。

在这里插入图片描述
如果希望查找到x值位于10和20之间的所有文档,直接想到的查询方式是使用db.a.find({"x":{$gt:10, $lt:20}}),希望这个查询返回文档是{"x": 15},但是,实际返回了两个文档:
在这里插入图片描述
5和25都不位于10和20之间,但是这个文档也返回了,因为25与查询条件中的第一个语句(大于10)相匹配,5与查询条件中的第二个语句(小于20)相匹配。

所以:对数组使用范围查询没有用;范围会匹配任意多元数组

其它方案:

可以使用$eleMatch,同时使用多个条件与数组元素进行比较:
在这里插入图片描述
但是有一个问题,$elemMatch不会匹配非数组元素。{“x”:15}它的x字段不是数组。

limit方法

limit()方法可以限制返回条数:
在这里插入图片描述

skip()方法

skip()方法可以从指定记录处开始显示(从0开始计数)

如:从第3条记录开始显示
在这里插入图片描述

skip()和limit()一起使用可以达到分页的效果
在这里插入图片描述
但是一般不建议这样使用,跳过的数据过多时,查询速度会变得很慢。

sort方法

sort方法接受一个对象作为参数,这个对象是一组键值对,键对应文档的键名,值代表排序的方向。排序方向可以是1(升序)或者-1(降序)。如果制订了多个键,则按照这些键被指定的顺序煮个排序。
在这里插入图片描述

带$in运算符的查询

$in运算符可以实现或(or)条件查找

实例:查找name为tom或jerry的记录
在这里插入图片描述

比较顺序:
MongoDB处理不同类型的数据是有一定序的。有时一个键的值可能是多种类型的,例如,整型和布尔型,或者字符串和nul。如果对这种混合类型的键排序,其排序顺序是预先定义好的。优先级从小到大,其顺序如下:

  1. 最小值
  2. null
  3. 数字(整形、长整型、双精度)
  4. 字符串
  5. 对象/文档
  6. 数组
  7. 二进制数据
  8. 对象ID
  9. 布尔型
    10.日期型
  10. 时间戳
  11. 正则表达式
  12. 最大值
通过查询操作符来查询

公共查询条件:{<key1>:{<operator1>:<value1>}, ...}

操作符格式实例类似的SQL语句
小于{<key>:{$lt:<value>}}db.xxx.find({price:{$lt:15}})where price < 15
小于等于{<key>:{$lte:<value>}}db.xxx.find({price:{$lte:15}})where price <= 15
大于{<key>:{$gt:<value>}}db.xxx.find({price:{$gt:15}})where price > 15
大于等于{<key>:{$gte:<value>}}db.xxx.find({price:{$gte:15}})where price >= 15
不等于{<key>:{$ne:<value>}}db.xxx.find({price:{$ne:15}})where price != 15
与(and){key1:value1, key2:value2,...}db.xxx.find({name:"tom", age:18})where name=“tome” and age=18
或(or){$or:[{key1:value1}, {key2:value2},...]}{db.xxx.find({$or:[{name:"tom"}, {age:28}]})}where name=“tom” or age=18
正则表达式<key>:{$regex:/pattern/<options>}

<key>:{$regex:'pattern'<options>}
如下表如下表
pattern选项实例类似的SQL语句
/查询值的固定后一部分$/db.xxx.find({name:{$regex:/tom$/}})where name like “%tom”
/^查询值的固定前一部分/db.xxx.find({name:{$regex:/^t/}})where name like “t%”
/查询值的任意部分/db.xxx.find({name:{$regex:/o/}})where nam like “%o%”
options选项实例选项说明
idb.xxx.find({name:{$regex:/^t/i}})不分区大小写
mdb.xxx.find({name:{$regex:/^t/, $options:"m"}})在一个文档值存在多字符串记录的情况下(中间以\n或$分隔),以记录为单位,匹配符合的文档记录。如果文档中不包含\n或$,则m选项不起作用
xdb.xxx.find({name:{$regex:/a/, $options:"x"}})在字符串文档值中,忽略有空格的、hash值的或带#的文档记录
sdb.xxx.find({name:{$regex:/^.*C/, $options:"si"}})在多字符串记录情况下,使用s可以做到pattern带".*"情况下的多字符串匹配
区间条件查找

查询年龄在15~30之间的人员记录:

在这里插入图片描述

$where查询

$where可以在查询中执行任意的JavaScript。为安全起见,应该限制或者消除$where语句的使用。

$where语句最常见的应用就是比较文档中两个不同见的值是否相等。

假如有如下文档:
在这里插入图片描述

查询两个键具有相同值的文档,比如第二个文档中spinach:4与watermolon:4值相等:
在这里插入图片描述
如果函数返回true,文档就作为结果集的一部分返回;如果为false,就不返回。

不是非常必要时,一定要避免使用"$where"查询,因为它们在速度上要比常规查询慢很多。每个文档都要从BSON转换成JavaScript对象,然后通过"$where"表达式来运行。而且"$where"语句不能使用索引,所以只在走投无路时才考虑"$where"这种用法。先使用常规查询进行过滤,然后再使用" w h e r e " 语句,这样组合使用可以降低性能损失。如果可能的话,使用 " where"语句,这样组合使用可以降低性能损失。如果可能的话,使用" where"语句,这样组合使用可以降低性能损失。如果可能的话,使用"where"语句前应该先使用索引进行过滤,“$where” 只用于对结果进行进一步过滤。

游标

数据库使用游标返回find的执行结果。客户端对游标的实现通常能够对最终结果进行有效的控制。可以限制结果的数量,略过部分结果,根据任意键按任意顺序的组合对结果进行各种排序,或者是执行其他一些强大的操作。

要想从 shell I中创建一个游标,首先要对集合填充一些文档,然后对其执行查询,并将结果分配给一个局部变量(用var声明的变量就是局部变量)。这里,先创建个简单的集合,而后做个查询,并用 cursor变量保存结果

在这里插入图片描述

这么做的好处是可以一次查看一条结果。如果将结果放在全局变量或者就没有放在变量中, MongoDB shell会自动迭代,自动显示最开始的若干文档。也就是在这之前我们看到的种种例子,一般大家只想通过shel看看集合里面有什么,而不是想在其中实际运行程序,这样设计也就很合适。

要迭代结果,可以使用游标的next方法。也可以使用hasNext来查看游标中是否还有其他结果。典型的结果遍历如下所示:
在这里插入图片描述
在这里插入图片描述

另外,调用find时,shell并不立即查询数据库,而是等待真正开始要求获得结果时才发送查询,这样在执行之前可以给查询附加额外的选项。

高级查询选项

有两种类型的查询:简单查询(plain query)和封装查询(wrapped query)。简单查询就像下面这样:

var cursor db.foo.find({"foo":"bar"})

有一些选项可以用于对查询进行“封装”。例如,假设我们执行一个排序:

var cursor db.foo.find({"foo""bar"}).sort({"x"1})

实际情况不是将{“foo”:“bar”}作为查询直接发送给数据库,而是先将查询封装在一个更大的文档中。shell会把查询从{“foo”:“bar”}转换成{"$query":{"foo":"bar"},"sorderby":{"x"1}}
绝大多数驱动程序都提供了辅助函数,用于向查询中添加各种选项。下面列举了其他一些有用的选项。

  • $maxscan:integer

执行本次查询中扫描文档数量的上限:

db.foo.find(criteria)._addSpecial("$maxscan", 20)

如果不希望查询耗时太多,也不确定集合中到底有多少文档需要扫描,那么可以使用这个选项。这样就会将查询结果限定为与被扫描的集合部分相匹配的文档。这种方式的一个坏处是,某些你希望得到的文档没有扫描到。

  • $min:document

查询的开始条件。在这样的查询中,文档必须与索引的键完全匹配。查询中会强制使用给定的索引。
在内部使用时,通常应该使用"$gt"代替"$min"。可以使用"$min"强制指定一次索引扫描的下边界,这在复杂查询中非常有用。

  • $max:document

查询的结束条件。在这样的查询中,文档必须与索引的键完全匹配。查询中会强制使用给定的索引。
在内部使用时,通常应该使用"$\lg"而不是"$max"。可以使用"$max"强制指定一次索引扫描的上边界,这在复杂查询中非常游泳。

  • $showDiskLoc:true
    在查询结果中添加一个"$diskLoc"字段,用于显示该条结果在磁盘上的位置。

在这里插入图片描述

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值