返回顶部

mongodb 权威指南 find

find 简介

指定要返回的键

有时候并不需要返回文档中的所有键–值对。遇到这种情况时,可以通过 find(或者 findOne)的第二个参数来指定需要的键。这样做既可以节省网络传输的数据量,也可以减少客户端解码文档的时间和内存消耗

 从以上输出可以看到,默认情况下 "_id" 键总是会被返回,即使没有指定要返回这个键

 也可以用第二个参数来剔除查询结果中的某些键–值对。例如,可能在文档中有很多键,而你不希望结果中包含"fatal_weakness" 键:

 查询条件

"$lt"、"$lte"、"$gt" 和 "$gte" 都属于比较运算符,分别对应<、<=、> 和 >=。可以将它们组合使用以查找一个范围内的值。例如,要查询 18 到 30 岁的用户,可以进行如下操作:

 对于文档键值不等于某个特定值的情况,就要使用另外一种条件运算符 "$ne" 了,它表示“不相等”。如果想找到所有用户名不为 joe 的用户,可以像下面这样查询:

 "$ne" 可以用于任何类型的数据

OR查询

MongoDB 中有两种方式可以进行 OR 查询。"$in" 可以用来查询一个键的多个值。"$or" 则更通用一些,可以在多个键中查询任意的给定值。如果一个键需要与多个值进行匹配,那么可以将一个条件数组与 "$in" 一起使用。假设我们正在进行一个抽奖活动,中奖号码是 725、542 和 390。要找出全部 3 个文档,可以构建如下查询:

 与 "$in" 相反的是 "$nin",此运算符会返回与数组中所有条件都不匹配的文档。如果想返回所有没有中奖的人,可以这样进行查询:

 "$or" 条件运算符。"$or" 会接受一个包含所有可能条件的数组作为参数。在上面的抽奖活动例子中,使用 "$or"会是这样:

 "$not" 是一个元条件运算符:可以用于任何其他条件之上。以取模运算符 "$mod" 为例,"$mod" 会将查询的值除以第一个给定值,如果余数等于第二个给定值,则匹配成功:

 以上查询会返回 "id_num" 为 1、6、11、16 等值的用户。如果要返回 "id_num" 为 2、3、4、5、7、8、9、10、12 等值的用户,则可以使用 "$not":

 在与正则表达式(4.3.2 节会详细讲述正则表达式的使用)联合使用以查找那些与特定模式不匹配的文档时,"$not" 尤其有用

特定类型的查询

MongoDB 在一个文档中可以使用多种类型的数据,其中一些类型在查询时会有特别的行为

null 的行为有一些特别。它可以与自身匹配,所以如果有一个包含如下文档的集合

不过,null 同样会匹配“不存在”这个条件。因此,对一个键进行 null 值的请求还会返回缺少这个键的所有文档

 如果仅想匹配键值为 null 的文档,则需要检查该键的值是否为null,并且通过 "$exists" 条件确认该键已存在

查询数组

查询数组元素的方式与查询标量值相同。假设有一个数组是水果列表,如下所示:

 则下面的查询可以成功匹配到该文档

 这个查询就好像对一个这样的(不合法)文档进行查询:{"fruit" : "apple", "fruit" : "banana", "fruit" : "peach"}。

可以使用 "$all" 查询来找到同时包含元素 "apple" 和 "banana"的文档

 也可以使用整个数组进行精确匹配。不过,精确匹配无法匹配上元素丢失或多余的文档。例如,下面这样可以匹配之前的第一个文档

 但是下面这样就不行:

 

 如果想在数组中查询特定位置的元素,可以使用 key.index 语法来指定下标

 数组下标都是从 0 开始的,因此这个语句会用数组的第 3 个元素与字符串 "peach" 进行匹配

"$size"

"$size" 条件运算符对于查询数组来说非常有用,可以用它查询特定长度的数组,如下所示。

 一种常见的查询是指定一个长度范围。"$size" 并不能与另一个$ 条件运算符(如 "$gt")组合使用,但这种查询可以通过在文档中添加一个 "size" 键的方式来实现。之后每次向指定数组添加元素时,同时增加 "size" 的值。如果原本的更新是这样

 那么可以很容易地转换成这样

 自增操作的速度非常快,因此任何性能损失都可以忽略不计。这样存储文档后就可以执行如下查询:

 很遗憾,这种技巧无法与 "$addToSet" 运算符联合使用

"$slice"

正如本章前面提到的,find 的第二个参数是可选的,可以指定需要返回的键。这个特别的 "$slice" 运算符可以返回一个数组键中元素的子集。假设现在有一个关于博客文章的文档,我们希望返回前 10 条评论:

 同样,如果想返回后 10 条评论,则可以使用 -10

 "$slice" 也可以指定偏移量和返回的元素数量来获取数组中间的结果

 查询内嵌文档

查询整个内嵌文档的工作方式与普通查询相同。假设有这样一个文档:

 可以使用点表示法对内嵌文档的键进行查询

 随着文档结构变得越来越复杂,内嵌文档的匹配可能会变得有点儿棘手。假设我们正在存储博客文章,要找到 Joe 发表的 5分以上的评论。可以按照以下方式对文章进行建模:

 这时,不能直接使用 db.blog.find({"comments" : {"author" :"joe", "score" : {"$gte" : 5}}}) 进行查询。内嵌文档的匹配必须匹配整个文档,而这个查询不会匹配 "comment" 键。使用db.blog.find({"comments.author" : "joe","comments.score" : {"$gte" : 5}}) 也不行,因为符合作者条件的评论与符合分数条件的评论可能不是同一条。也就是说,这会返回上面显示的那个文档:因为它匹配了第一条评论中的"author" : "joe" 和第二条评论中的 "score" : 6。要正确指定一组条件而无须指定每个键,请使用"$elemMatch"。这种模糊的命名条件允许你在查询条件中部分指定匹配数组中的单个内嵌文档。正确的查询如下所示

 "$elemMatch" 允许你将限定条件进行“分组”。仅当需要对一个内嵌文档的多个键进行操作时才会用到它。

游标

limit、skip和sort

最常用的查询选项是限制返回结果的数量、略过一定数量的结果以及排序。所有这些选项必须在查询被发送到数据库之前指定。要限制结果数量,可以在 find 之后链式调用 limit 函数。如果只返回 3 个结果,那么可以这样做:

 如果集合中所匹配的文档不到 3 个,则仅返回匹配数量的结果。limit 指定的是上限,而不是下限

skip 与 limit 类似:

 这个操作会略过前 3 个匹配的文档,然后返回剩下的文档。如果集合中匹配的文档少于 3 个,则不会返回任何文档。sort 会接受一个对象作为参数,这个对象是一组键–值对,键对应文档的键名,值对应排序的方向。排序方向可以是 1(升序)或 -1(降序)。如果指定了多个键,则结果会按照这些键被指定的顺序进行排序。例如,要按照 "username" 升序及 "age"降序排列,可以这样做:

不要使用skip进行分页

使用 skip 来略过少量的文档是可以的。但对于结果非常多的情况,skip 会非常慢,因为需要先找到被略过的结果,然后再丢弃这些数据。大多数数据库会在索引中保存更多的元数据以处理 skip,但 MongoDB 目前还不支持这样做,所以应该避免略过大量的数据。通常下一次查询的条件可以基于上一次查询的结果计算出来

最简单的分页方式是使用 limit 返回结果的第 1 页,然后将每个后续页面作为相对于开始的偏移量进行返回

数组嵌套更新

插入数据

db.posts.insert({
    "contemt": "mongodb",
    "comments": [
        {"comment":"good mongodb", "author":"John1"},
        {"comment":"i thought it was too large", "author":"david", "id":5},
        {"comment":"free watches mongodb", "author":"alice1"},
        {"comment":"vacation getaways mongodb", "author":"lynn1"}
        ]
}) 

更新数组中 author为 david json (整体替换)

db.posts.updateOne({"comments.author":"david2"}, {"$set":{"comments.$":{"comment":"update david to david2", "author":"david2", "id":5, "text":"one text"}}})  

查询更新后的数

 更新数组中 author为 david2 json 的某一个值

db.posts.updateOne({"comments.author":"david2"}, {"$set":{"comments.$.id": 2, "comments.$.text":"two text"}})

查询更新后的数据

 

posted @ 2022-05-05 22:53  Crazymagic  阅读(205)  评论(0)    收藏  举报