程序员书籍笔记 程序员书籍笔记
  • JavaScript
  • HTML/CSS
  • PHP
  • Python
  • Go
  • 数据库
  • 容器
  • 微服务
  • 消息队列
  • 搜索引擎
  • 大数据
  • 鸟哥Linux私房菜
其他
  • 大数据
  • 深度学习
APP下载 (opens new window)
GitHub (opens new window)
  • JavaScript
  • HTML/CSS
  • PHP
  • Python
  • Go
  • 数据库
  • 容器
  • 微服务
  • 消息队列
  • 搜索引擎
  • 大数据
  • 鸟哥Linux私房菜
其他
  • 大数据
  • 深度学习
APP下载 (opens new window)
GitHub (opens new window)
  • 数据库

    • MySQL必知必会

    • MongoDB权威指南

      • 入门
      • 文档创建、更新、删除
      • 查询
        • find简介
          • 返回指定的键
          • 限制
        • 查询条件
          • 查询条件
          • OR查询
          • $NOT
          • 条件句的规则
        • 特定类型的查询
          • null
          • 正则表达式
          • 查询数组
          • 查询内嵌文档
        • $where查询
        • 游标
          • limit,skip,sort
          • 避免使用SKIP略过大量结果
          • 高级查询选项
          • 获取一致结果
        • 游标内幕
      • 索引
      • 聚合
  • 容器

  • 微服务

  • 消息队列

  • 搜索引擎

  • 大数据

  • 框架和软件
  • 数据库
  • MongoDB权威指南
小游
2021-05-13

查询

# find简介

查询所有的文档可以使用下面的命令

db.test.find({})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "like" : []
}
1
2
3
4
5
6
7

如果想查询特定内容,比如name为小游的文档

db.test.find({"name":"小游"})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "like" : []
}
1
2
3
4
5
6
7

# 返回指定的键

如果我们只需要name字段,我们可以这样,默认_id会返回,我们可以置为0,避免返回

db.test.find({},{"name":1,"_id":0})
/* 1 */
{
    "name" : "小游"
}
1
2
3
4
5

# 限制

查询文档的值必须是常量,也就是不能引用文档中其他键的值。

# 查询条件

# 查询条件

image-20210513153123744

db.test.find({"age":{"$gte":18,"$lte":30}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : []
}
1
2
3
4
5
6
7
8

# OR查询

我们可以使用 "$in" 来查询一个键的多个值。也可以使用 "$OR" 一般来说OR会通用一些。

db.test.find({"age":{"$in":[20,100]}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : []
}

/* 2 */
{
    "_id" : ObjectId("609cd4df71a920015b3da7ac"),
    "name" : "张三",
    "age" : 100,
    "like" : []
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

与 $in 相对的是 $nin ,会返回不匹配的文档。但是这个只能查询单个条件,下面我们来使用 or 查询年龄在20或者名字为张三的人

db.test.find({"$or":[{"age":{"$in":[20]}},{"name":"张三"}]})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : []
}

/* 2 */
{
    "_id" : ObjectId("609cd4df71a920015b3da7ac"),
    "name" : "张三",
    "age" : 100,
    "like" : []
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# $NOT

这个是原语句,可以用在其他任何条件上

db.test.find({"age":{"$not":{"$in":[20]}}})
/* 1 */
{
    "_id" : ObjectId("609cd4df71a920015b3da7ac"),
    "name" : "张三",
    "age" : 100,
    "like" : []
}
1
2
3
4
5
6
7
8

# 条件句的规则

条件句是内层文档的键,修改器是外层文档的键

# 内层文档
db.test.find({"age":{"$not":{"$in":[20]}}})
# 外层文档
db.test.update({"name":"小游"},{"$set":{"age":0}})
1
2
3
4

image-20210513154226719

# 特定类型的查询

# null

image-20210513154325317

image-20210513154334442

# 正则表达式

查询条件可以直接设置为正则表达式,用于灵活有效的匹配字符串

db.test.find({"name":/小/i})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : []
}
1
2
3
4
5
6
7
8

# 查询数组

db.test.find({"like":"看番"})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码", 
        "看番"
    ]
}
1
2
3
4
5
6
7
8
9
10
11

如果想匹配多个数组,可以使用 $all 来进行匹配,里面的内容是没有顺序的

db.test.find({"like": {"$all":["写代码","看番"]}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码", 
        "看番"
    ]
}
# 下面这个语句匹配不到内容
db.test.find({"like": {"$all":["写代码","看番","玩"]}})
1
2
3
4
5
6
7
8
9
10
11
12
13

如果想查询指定长度的数组,可以使用 $size

db.test.find({"like": {"$size":2}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码", 
        "看番"
    ]
}
1
2
3
4
5
6
7
8
9
10
11

如果只想返回数组的前一个元素,可以使用 $slice 操作符,当然也可以知道偏移值

db.test.find({"name":"小游"},{"like":{"$slice":1}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码"
    ]
}

# 使用偏移值,跳过前一个元素,返回一个元素
db.test.find({"name":"小游"},{"like":{"$slice":[1,1]}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "看番"
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 查询内嵌文档

db.test.find({"name.first":"小"})
/* 1 */
{
    "_id" : ObjectId("609cd4df71a920015b3da7ac"),
    "name" : {
        "first" : "小",
        "last" : "游"
    },
    "age" : 100,
    "like" : []
}
1
2
3
4
5
6
7
8
9
10
11

# $where查询

where查询可以执行任意JavaScript语句作为查询的一部分。如果return为真,就返回这条数据,否则就不返回

db.test.find({"$where":function(){
    return this.name === "小游"
}})
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码", 
        "看番"
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13

当然我们也可以使用一个字符串来指定where查询

db.test.find({"$where":"this.name === '小游'"})
1

# 游标

数据库会使用游标来返回find的执行结果,我们可以对这个cursor对象进行遍历操作

var cursor=db.test.find({})
cursor.forEach(function(x){
    print(x.name)
})
小游
张三
# 也可以这样进行操作,返回的记过都是一样的
var cursor=db.test.find({})
while(cursor.hasNext()){
    print(cursor.next().name);
}
1
2
3
4
5
6
7
8
9
10
11

# limit,skip,sort

最常用的查询选项就是限制返回结果的数量,忽略一定数量的结果并排序。所有这些选项一定要在查询被派发到服务器之前添加,比如我们只想返回一个结果

db.getCollection('test').find({}).limit(1)
/* 1 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码", 
        "看番"
    ]
}
1
2
3
4
5
6
7
8
9
10
11

skip可以跳过文档,比如我们跳过第一个文档

db.getCollection('test').find({}).skip(1)
/* 1 */
{
    "_id" : ObjectId("609cd4df71a920015b3da7ac"),
    "name" : "张三",
    "age" : 100,
    "like" : []
}
1
2
3
4
5
6
7
8

sort 可以设置排序,1为升序,-1为降序

db.getCollection('test').find({}).sort({_id:-1})
/* 1 */
{
    "_id" : ObjectId("609cd4df71a920015b3da7ac"),
    "name" : "张三",
    "age" : 100,
    "like" : []
}

/* 2 */
{
    "_id" : ObjectId("609bb9f16ac4daf1370a10c6"),
    "name" : "小游",
    "age" : 20,
    "like" : [ 
        "写代码", 
        "看番"
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

如果一个键有多个值,那么MongoDB的比较顺序如下

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

# 避免使用SKIP略过大量结果

用skip略过少量的文档还是不错的。但是要是数量非常多的话,skip就会变得很慢(几乎每个数据库都有这个问题,不仅仅是 MongoDB),所以要尽量避免。通常可以向文档本身内置查询条件,来避免过大的skip,或者利用上次的结果来计算下一次查询。

不用skip对结果分页

通常情况下我们会使用skip对结果进行分页,比如下面这个

image-20210514192400794

我们也可以使用下面这种方式来进行分页

image-20210514192453602

我们只需要记住一个时间点,然后找出比这个时间点大的,在使用limit进行分页操作。

随机选取文档

如果想随机选取文档,我们其实可以在文档里面加一个字段,然后在查询,这样就可以实现随机文档的效果了

image-20210514192719340

# 高级查询选项

查询分类包装查询和普通查询两种

// 普通查询
var cursor=db.foo.find({"foo :"bar"})
// 包装查询
var cursor db.foo.find({"foo":"bar"}). sort({"x":1})
1
2
3
4

实际情况不是将{"foo":"bar"}作为查询直接发送给数据库,而是将查询包装在一个更大的文档中。shell会把查询从{"foo":"bar"}转换成{"$query":{"fool":"bar"},"$orderby" :{"x":1}}

# 获取一致结果

数据处理通常的一种做法就是先把数据从 MongoDB中取出来,然后经过某种变换最后再存回去,结果少的话还好,但是一旦结果一多,因为之前的空间是固定的,我们修改文档后,空间比原来的大,这个时候MongoDB就会移动文档,找出游标返回的数据不一致的问题

应对这个问题的方法就是对查询进行快照。如果使用了“$snapshot”选项,查询就是针对不变的集合视图运行的。所有返回一组结果的查询实际上都进行了快照。不一致只在游标等待结果时集合内容被改变的情况下发生。

# 游标内幕

image-20210514193557315

编辑 (opens new window)
上次更新: 2021/05/14, 21:28:33
文档创建、更新、删除
索引

← 文档创建、更新、删除 索引→

Theme by Vdoing | Copyright © 2021-2021 小游
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式