1285 lines
46 KiB
Markdown
1285 lines
46 KiB
Markdown
---
|
||
title: MongoDB基础
|
||
date: 2020-12-29
|
||
author: ac
|
||
tags:
|
||
- MongoDB
|
||
categories:
|
||
- Database
|
||
---
|
||
|
||
## 一、简介
|
||
|
||
`MongoDB`是一个开源、高性能、无模式(没有确定的列)的文档型数据库,设计之初是为了简化开发和方便扩展,是`NoSQL`数据库产品中的一种。是最像关系型数据库的非关系型数据库。
|
||
|
||
它支持的数据库结构非常松散,是一种类似`JSON`格式的`BSON`,所以它既可以存储比较复杂的数据类型,又相当的灵活。
|
||
|
||
`MongoDB`中的记录是一个文档,它是一个由记录和键值对(`filed`:`value`)组成的数据结构。`MongoDB`文档类似于`JSON`对象,即一个文档可以认为就是一个对象。字段的数据类型是字符型,它的值除了使用一些类型外,还可以包括其他文档、普通数组和文档数组。
|
||
|
||
### 体系结构
|
||
|
||
**关系型数据库与`MongoDB`的对比**
|
||
|
||
| SQL术语/概念 | MongoDB | 描述 |
|
||
| ------------ | ----------- | ---------------------------------------- |
|
||
| database | database | 数据库 |
|
||
| table | collection | 数据库表/集合 |
|
||
| row | document | 数据记录行/文档 |
|
||
| column | field | 数据字段/域 |
|
||
| index | index | 索引 |
|
||
| table joins | | 表连接,`MongoDB`不支持 |
|
||
| | 嵌入文档 | `MongoDB`通过嵌入式文档来替代多表连接 |
|
||
| primary key | primary key | 主键,`MongoDB`自动将`_id`字段设置为主键 |
|
||
|
||
### 数据模型
|
||
|
||
`MongoDB`的最小存储单位是文档(document)对象。
|
||
|
||
文档对象对应关系型数据库中的行。数据在`MongoDB`中是以`BSON`(Binary-JSON)文档的格式存储在磁盘上的。
|
||
|
||
`BSON`(Binary Serizlized Document Format)是一种类`JSON`的二进制形式的存储格式,简称Binary JSON。跟`JSON`一样,支持内嵌的文档对象和数组对象,但是`BSON`有`JSON`没有的数据类型,如`Date`、`BinData`。
|
||
|
||
`BSON`采用类似于C语言结构体的名称、对表示方法,支持内嵌的文档对象和数组对象,具有轻量级、可遍历性、高效性的三个特点,可以有效地描述非结构化数据和结构化数据。优点是灵活性高,但缺点是空间利用率不是很理想。
|
||
|
||
`BSON`中,除了支持基本的JSON类型(string、integer、boolean、double、null、array、object)外,还有特殊的数据类型,如:date、object id、binary data、regular expression、code。
|
||
|
||
`BSON`数据类型:
|
||
|
||
| 数据类型 | 描述 | 举例 |
|
||
| ------------- | ------------------------------------------------------------ | ---------------------------------------------------- |
|
||
| 字符串 | UTF-8字符串都可以表示为字符串类型的数据 | {"x":"type"} |
|
||
| 对象id | 对象id是文档的12字节的唯一ID | {"X":ObjectId()} |
|
||
| 布尔值 | true、false | {"x":true} |
|
||
| 数组 | 值的集合或列表可以表示的数组 | {"x":["a":"b":"c"]} |
|
||
| 32位整数 | 类型不可用。JavaScript仅支持64位浮点数,所以32位整数会被 | shell是不支持该类型的,shell中默认会转换成64位浮点数 |
|
||
| 64位整数 | 不支持这个类型。shell会使用一个特殊的内嵌文档来显示64位 | shell是不支持该类型的,shell中默认会转换成64 |
|
||
| 64位浮点数 | shell中的数字就是这一种类型 | {"x":3.14159,"y":3} |
|
||
| null | 表示空值或者未定义的对象 | {"x":null} |
|
||
| undefined | 文档中也可以使用未定义类型 | {"x":undefined} |
|
||
| 符号 | shell不支持,shell会将数据库中的符号类型的数据自动换成字符串 | |
|
||
| 正则表达式 | 文档中可以包含正则表达式,采用JavaScript的正则表达式语法 | {"x":/type/i} |
|
||
| 代码 | 文档中可以包含JavaScript代码 | {"x":function(){}} |
|
||
| 二进制数据 | 二进制数据可以由任意字节的串组成,不过shell中无法使用 | |
|
||
| 最大值/最小值 | BSON包括一个特殊类型,表示可能的最大值。shell中没有这个类型 | |
|
||
|
||
> shell默认使用64位浮点型数值。对于整型值,可以使用`NumberInt`(4字节符号整数)或`NumberLong`(8字节符号整数),如{"x":NumberInt("3")}、{"x":NumberLong("3")}
|
||
|
||
### 特点
|
||
|
||
- 高性能
|
||
- 高可用
|
||
- 高扩展
|
||
- 丰富的查询支持
|
||
- 无模式(动态模式)、灵活的文档模型
|
||
|
||
|
||
|
||
## 二、安装部署
|
||
|
||
> 这里先介绍单机部署
|
||
|
||
### windows系统
|
||
|
||
1. 下载安装包
|
||
|
||
`MongoDB`提供了可用于32位和64位系统的预编译二进制包。官网下载[社区版](https://www.mongodb.com/try/download/community),On-Premises(内部部署):
|
||
|
||

|
||
|
||
我们选择下载`zip`包格式的压缩包。
|
||
|
||
> MongoDB 的版本命名规范如:x.y.z;
|
||
>
|
||
> y为奇数时表示当前版本为开发版,如:1.5.2、4.1.13;
|
||
>
|
||
> y为偶数时表示当前版本为稳定版,如:1.6.3、4.0.10;
|
||
>
|
||
> z是修正版本号,数字越大越好。
|
||
|
||
2. 解压安装启动
|
||
|
||
将压缩包解压到一个目录中,手动创建一个目录用于存放数据文件,如`data/db`
|
||
|
||
启动方式有两种:
|
||
|
||
- 在`bin`目录下,打开`cmd`命令行,输入命令
|
||
|
||
```shell
|
||
mongod --dbpath=..\data\db
|
||
```
|
||
|
||
这样`MongoDB`会被启动,默认端口是27017,如果需要修改端口可以添加 `--port`参数来指定端口。
|
||
|
||
如果缺少`vcruntime140_1.dll`文件会出现下面的错误,解决方式是从网上下载该文件复制到`C:\Windows\System32`目录下就可以。
|
||
|
||

|
||
|
||
|
||
|
||
- 使用配置文件的方式启动服务
|
||
|
||
在解压的目录下创建`config`文件夹,并在该目录下新建`mongod.conf`文件,内容如下:
|
||
|
||
```yml
|
||
storage:
|
||
dbPath: C:\D\mongodb-win32-x86_64-windows-4.4.2\data\db
|
||
```
|
||
|
||
详细配置文件和配置项。请参考[官方文档](https://docs.mongodb.com/manual/reference/configuration-options/)。
|
||
|
||
> 注意:
|
||
>
|
||
> `yml`配置文件中不能使用`tab`键分割字段
|
||
>
|
||
> 配置文件中如果使用双引号,比如路径地址,自动会将双引号的内容转义。如果不转义,则会报错,解决方法是:
|
||
>
|
||
> - 将`\`换成`/`或`\\`
|
||
> - 如果路径中没有哦空格,则无需加引号
|
||
|
||
启动命令:
|
||
|
||
```shell
|
||
mongod -f ../config/mongod.conf
|
||
或
|
||
mongod --config ../config/mongod.conf
|
||
```
|
||
|
||
更多参数配置:
|
||
|
||
```yml
|
||
systemLog:
|
||
#MongoDB发送所有日志输出到的目的地。指定file或syslog。
|
||
#如果指定了file,还必须指定systemLog.path。
|
||
destination: file
|
||
path: "/var/log/mongodb/mongod.log"
|
||
#每次启动后输出的日志追加到上一次的日志文件中
|
||
logAppend: true
|
||
storage:
|
||
journal:
|
||
#启用或禁用持久性日志,以确保数据文件保持有效和可恢复。
|
||
#此选项仅在指定存储时适用。dbPath设置。mongod默认启用日志记录。
|
||
enabled: true
|
||
processManagement:
|
||
#启用后台运行mongos或mongod进程的守护模式
|
||
fork: true
|
||
net:
|
||
#主机名和/或IP地址和/或完整的Unix域套接字路径,mongos或mongod应该在其上监听客户端连接。
|
||
#你可以将mongos或mongod附加到任何接口。要绑定到多个地址,请输入以逗号分隔的值列表。
|
||
bindIp: 127.0.0.1
|
||
port: 27017
|
||
setParameter:
|
||
enableLocalhostAuthBypass: false
|
||
```
|
||
|
||
|
||
|
||
### Shell连接(mongo命令)
|
||
|
||
在命令提示符输入`mongo`命令完成登陆
|
||
|
||
```shell
|
||
monogo
|
||
或
|
||
mongo --host=127.0.0.1 --port=27017
|
||
```
|
||
|
||
查看已存在的数据库
|
||
|
||
```shell
|
||
show database
|
||
```
|
||
|
||
退出`mongodb`
|
||
|
||
```shell
|
||
exit
|
||
```
|
||
|
||
> MongoDB JavaScript shell 是一个基于JavaScript的解释器,所以支持JS程序
|
||
|
||
|
||
|
||
### Compass图形化界面客户端
|
||
|
||
[MongoDB Compass](https://www.mongodb.com/try/download/compass?initial=true)是`MongoDB`数据库的图形化管理工具。可以下载`zip`压缩版本,解压后双击`MongoDBCompass.exe`运行。
|
||
|
||

|
||
|
||
> 标准的[connection-string](https://docs.mongodb.com/manual/reference/connection-string/)格式:`mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]`
|
||
>
|
||
> 示例:`mongodb://192.168.0.152:27017`
|
||
|
||
|
||
|
||
### Linux系统
|
||
|
||
在`linux`中部署一个单机的`MongoDB`,作为生产环境下使用。安装步骤跟`windows`下的差不多:
|
||
|
||
1. 下载压缩包,选择`tgz`压缩包的形式。
|
||
|
||

|
||
|
||
2. 上传压缩包至`linux`上,解压
|
||
|
||
```shell
|
||
tar -xvf mongodb-linux-x86_64-ubuntu2004-4.4.2.tgz
|
||
```
|
||
|
||
3. 将解压后的文件移动到指定的目录中
|
||
|
||
```shell
|
||
sudo mv mongodb-linux-x86_64-ubuntu2004-4.4.2 /usr/local/mongodb
|
||
```
|
||
|
||
4. 创建日志和数据的存储目录
|
||
|
||
```shell
|
||
#数据存储目录
|
||
sudo mkdir -p /mongodb/single/data/db
|
||
|
||
#日志目录
|
||
sudo mkdir -p /mongodb/single/log
|
||
```
|
||
|
||
5. 创建启动配置文件
|
||
|
||
```shell
|
||
#查看配置参数
|
||
/usr/local/mongodb/bin/mongod --help
|
||
|
||
#新建配置文件
|
||
vi /mongodb/single/mongod.conf
|
||
```
|
||
|
||
```yml
|
||
systemLog:
|
||
destination: file
|
||
path: "/home/qiusj/.local/mongodb/singlesite/log/mongodd.log"
|
||
logAppend: true
|
||
storage:
|
||
dbPath: "/home/qiusj/.local/mongodb/singlesite/data/db"
|
||
journal:
|
||
enabled: true
|
||
net:
|
||
#添加本机在局域网内的ip
|
||
bindIp: 127.0.0.1,192.168.0.152
|
||
port: 27017
|
||
setParameter:
|
||
enableLocalhostAuthBypass: false
|
||
processManagement:
|
||
fork: true
|
||
```
|
||
|
||
折腾的比较久,发现路径有问题(应该是没有权限,打不开文件)。换了路径解决问题。
|
||
|
||
6. 启动`MongoDB`服务/usr
|
||
|
||
```shell
|
||
qiusj@u20:~$ /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/singlesite/mongod.conf
|
||
about to fork child process, waiting until server is ready for connections.
|
||
forked process: 447853
|
||
child process started successfully, parent exiting
|
||
```
|
||
|
||
通过进程来查看服务是否启动:
|
||
|
||
```shell
|
||
qiusj@u20:~$ ps -ef|grep mongod
|
||
qiusj 447853 1 0 15:16 ? 00:00:01 /usr/local/mongodb/bin/mongod -f /home/qiusj/.local/mongodb/mongod.conf
|
||
```
|
||
|
||
7. 使用`mongo`命令和compass工具连接
|
||
|
||
> 外部链接需要设置防火墙,开放端口
|
||
|
||
```shell
|
||
#ubuntu使用的是ufw,status查看ufw防火墙的状态,allow允许扣个端口
|
||
sudo ufw status # 查看防火墙状态
|
||
sudo ufw allow 27017
|
||
```
|
||
|
||
8. 关闭服务
|
||
|
||
关闭服务有两种方式:
|
||
|
||
- 快速关闭:使用`kill`命令直接杀死进程
|
||
|
||
```shell
|
||
#通过进程编号关闭节点
|
||
kill -2 进程号
|
||
```
|
||
|
||
|
||
|
||
- 标准关闭:通过`mongo`个客户端中的`shutdownServer`命令来关闭服务
|
||
|
||
```shell
|
||
#客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
|
||
mongo --port 27017
|
||
|
||
#切换到admin库
|
||
use admin
|
||
|
||
#如果不是admin数据库,则会报如下错误
|
||
shutdown command only works with the admin database; try 'use admin'
|
||
|
||
#关闭服务
|
||
db.shutdownServer()
|
||
```
|
||
### 数据修复
|
||
|
||
如果出现数据损坏的情况,可以通过下面操作进行修复:
|
||
|
||
1. 删除lock文件
|
||
|
||
```shell
|
||
#删除数据目录下面的`.lock`文件
|
||
rm -f /data/db/*.lock
|
||
```
|
||
|
||
2. 修复数据
|
||
|
||
```shell
|
||
/usr/local/mongdb/bin/mongod --repair --dbpath=/mongodb/single/data/db
|
||
```
|
||
|
||
|
||
|
||
## 三、基本命令
|
||
|
||
### 数据库操作
|
||
|
||
```shell
|
||
#选择和创建数据:use 数据库名称
|
||
use testdb
|
||
|
||
#查看有权限查看的所有数据库,磁盘中已经持久化了的数据库
|
||
show dbs
|
||
或
|
||
show databases
|
||
|
||
#查看当前数据库
|
||
db
|
||
|
||
#删除数据库
|
||
db.dropDatabase()
|
||
```
|
||
|
||
> 如果数据库不存在则会自动创建。自动创建的在没有集合前(空数据库)是存在内存中的。
|
||
>
|
||
> 默认的数据库是`test`,如果没有选择数据库,集合将存放在`test`数据库中
|
||
|
||
数据库名称的命名规范,必须是满足以下条件的任意`UTF-8`编码的字符串。
|
||
|
||
- 不能是空字符串("")
|
||
- 不得含有特殊字符(空格、$、/、\、\0)
|
||
- 全小写
|
||
- 最多64字节
|
||
|
||
**三个默认数据库的特殊作用**:
|
||
|
||
- **`admin`**:从权限的角度,这是`root`数据库,要是将一个用户添加到这个数据库,这个用户将自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或关闭服务器。
|
||
- **`local`**:这个数据库中的数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合。
|
||
- **`config`**:当`Mongo`用于分片设置时,`config`数据库在内部使用,用于保存分片的相关信息。
|
||
|
||
|
||
|
||
### 集合操作
|
||
|
||
集合,类似于关系型数据库中的表。可以显示创建,也可以隐式创建。
|
||
|
||
```shell
|
||
#创建名为article的集合
|
||
db.createCollection("article")
|
||
|
||
#查看当前库中的集合(表)
|
||
show collections
|
||
或
|
||
show tables
|
||
|
||
#删除集合,语法:db.集合.drop(),删除成功会返回true
|
||
db.article.drop()
|
||
```
|
||
|
||
集合的命名规范:
|
||
|
||
- 不能是空字符串""。
|
||
- 不能是空字符(\0)结尾的字符串
|
||
- 不能是以`system.`开头,因为这是给系统集合保留的前缀
|
||
- 不能含有保留字符
|
||
|
||
集合的隐式创建:
|
||
|
||
当向一个集合插入一个文档的时候,如果集合不存在,则会自动创建集合(这是最常用的方式)。
|
||
|
||
|
||
|
||
### 文档的CRUD
|
||
|
||
文档`document`的数据结构和`JSON`基本一样。所有存储在集合中的数据都是`BSON`格式。
|
||
|
||
#### 插入
|
||
|
||
文档的插入的方法有`insert()`、`save()`、`insertMany()`。
|
||
|
||
`insert`方法的语法:
|
||
|
||
```shell
|
||
db.collection.insert(
|
||
<document or array of documents>,
|
||
{
|
||
writeConcern:<document>,
|
||
ordered:<boolean>
|
||
}
|
||
)
|
||
```
|
||
|
||
参数列表:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
| -------------- | ------------------------ | ------------------------------------------------------------ |
|
||
| `doucment` | document 或document 数组 | 要插入到集合中的文档或文档数组 |
|
||
| `writeConcern` | document | Optional. A document expressing the [write concern](https://docs.mongodb.com/manual/reference/write-concern/). Omit to use the default write concern. See [Write Concern](https://docs.mongodb.com/manual/reference/method/db.collection.insert/#insert-wc).<br>Do not explicitly set the write concern for the operation if run in a transaction. To use write concern with transactions, see [Transactions and Write Concern](https://docs.mongodb.com/manual/core/transactions/#transactions-write-concern). |
|
||
| `ordered` | boolean | 可选。如果为真,则按顺序插入数组中的文档,如果其中一个文档出现错误,`MongoDB`将返回而不处理数组中的其余文档。如果为假,则执行无序插入,如果其中一个文档出现错误,则继续处理 |
|
||
|
||
示例:
|
||
|
||
```shell
|
||
> use meface
|
||
switched to db meface
|
||
> db
|
||
meface
|
||
> show collections
|
||
article
|
||
> db.article.insert({
|
||
"articleid": "100000",
|
||
"content": "今天天气真好,阳光明 媚",
|
||
"userid": "1001",
|
||
"nickname": "Rose",
|
||
"createdatetime": new Date(),
|
||
"likenum": NumberInt(10),
|
||
"state": null
|
||
})
|
||
WriteResult({ "nInserted" : 1 })
|
||
```
|
||
|
||
> 如果collection集合不存在,则会隐式创建
|
||
|
||
注意:
|
||
|
||
- `mongo`中的数字,默认情况下是`double`类型,如果要存储整型,必须使用函数`NumberInt(整型数值)`,否则取出来就有问题。
|
||
- 插入当前日期使用`new Date()`。
|
||
- 插入的数据没有指定`_id`,会自动生成主键值。
|
||
- 如果某字段没值,可以赋值为`null`,或不写该字段。
|
||
|
||
|
||
|
||
- 文档中的键/值对是有序的。
|
||
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个文档)。
|
||
- `MongoDB`区分类型和大小写。
|
||
- `MongoDB`的文档不能有重复的键。
|
||
- 文档的键是字符串,除了少数例外情况,键可以使用任意UTF-8字符
|
||
|
||
|
||
|
||
文档中键的命名规范:
|
||
|
||
- 键不能含有\0(空字符)。这个字符用来表示键的结尾。
|
||
- `.`和`$`有特殊的意义,只有在特定环境下才能使用。
|
||
- 以下划线`_`开头的键是保留的(不是严格要求的)
|
||
|
||
|
||
|
||
`insertMany`方法用于批量插入,语法:
|
||
|
||
```shell
|
||
db.collection.insertMany(
|
||
[ <document 1> , <document 2>, ... ],
|
||
{
|
||
writeConcern: <document>,
|
||
ordered: <boolean>
|
||
}
|
||
)
|
||
```
|
||
|
||
| Parameter | Type | Description |
|
||
| :------------- | :------- | :----------------------------------------------------------- |
|
||
| `document` | document | An array of documents to insert into the collection. |
|
||
| `writeConcern` | document | Optional. A document expressing the [write concern](https://docs.mongodb.com/manual/reference/write-concern/). Omit to use the default write concern.Do not explicitly set the write concern for the operation if run in a transaction. To use write concern with transactions, see [Transactions and Write Concern](https://docs.mongodb.com/manual/core/transactions/#transactions-write-concern). |
|
||
| `ordered` | boolean | Optional. A boolean specifying whether the [`mongod`](https://docs.mongodb.com/manual/reference/program/mongod/#bin.mongod) instance should perform an ordered or unordered insert. Defaults to `true`. |
|
||
|
||
示例:
|
||
|
||
```shell
|
||
#插入多条记录
|
||
db.article.insertMany([{
|
||
"_id": "1",
|
||
"articleid": "100001",
|
||
"content": "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。",
|
||
"userid": "1002",
|
||
"nickname": "相忘于江湖",
|
||
"createdatetime": new Date("2019-08- 05T22:08:15.522Z"),
|
||
"likenum": NumberInt(1000),
|
||
"state": "1"
|
||
}, {
|
||
"_id": "2",
|
||
"articleid": "100001",
|
||
"content": "我夏天空腹喝凉开水,冬天喝温开水",
|
||
"userid": "1005",
|
||
"nickname": "伊人憔 悴",
|
||
"createdatetime": new Date("2019-08-05T23:58:51.485Z"),
|
||
"likenum": NumberInt(888),
|
||
"state": "1"
|
||
}, {
|
||
"_id": "3",
|
||
"articleid": "100001",
|
||
"content": "我一直喝凉开水,冬天夏天都喝。",
|
||
"userid": "1004",
|
||
"nickname": "杰克船 长",
|
||
"createdatetime": new Date("2019-08-06T01:05:06.321Z"),
|
||
"likenum": NumberInt(666),
|
||
"state": "1"
|
||
}, {
|
||
"_id": "4",
|
||
"articleid": "100001",
|
||
"content": "专家说不能空腹吃饭,影响健康。",
|
||
"userid": "1003",
|
||
"nickname": "凯 撒",
|
||
"createdatetime": new Date("2019-08-06T08:18:35.288Z"),
|
||
"likenum": NumberInt(2000),
|
||
"state": "1"
|
||
}, {
|
||
"_id": "5",
|
||
"articleid": "100001",
|
||
"content": "研究表明,刚烧开的水千万不能喝,因为烫 嘴。",
|
||
"userid": "1003",
|
||
"nickname": "凯撒",
|
||
"createdatetime": new Date("2019-08- 06T11:01:02.521Z"),
|
||
"likenum": NumberInt(3000),
|
||
"state": "1"
|
||
}]);
|
||
```
|
||
|
||
> 插入时指定了`_id`,则主键为该键值。如果某条数据插入失败,将会终止插入,但已经插入成功的数据不会回滚。由于批量插入时数据量较大,容易出现失败,所以可以使用`try catch`进行异常捕捉处理。
|
||
|
||
|
||
|
||
#### 查询
|
||
|
||
文档的查询方法有很多,先来了解以下两个方法:
|
||
|
||
- `db.collection.find(query, projection)`:在集合或视图上执行一个查询并返回一个`cursor`游标对象
|
||
- `db.collection.findOne(query, projection)`:返回满足`query`条件的第一个文档
|
||
|
||
| Parameter | Type | Description |
|
||
| :----------- | :------- | :----------------------------------------------------------- |
|
||
| `query` | document | 可选, 一个`JSON`对象用于筛选文档,如查找userId为1001的文档{userId:"10001"} |
|
||
| `projection` | document | 可选,可以用于限定文档返回的键,{"articleid":1} |
|
||
|
||
示例:
|
||
|
||
```shell
|
||
#查询article集合中的所有文档
|
||
> db.article.find()
|
||
{ "_id" : ObjectId("5fed2b1b232584d8ba357db0"), "articleid" : "100000", "content" : "今天天气真好,阳光明 媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2020-12-31T01:36:27.784Z"), "likenum" : 10, "state" : null }
|
||
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我 他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("1970-01-01T00:00:00Z"), "likenum" : 1000, "state" : "1" }
|
||
...
|
||
```
|
||
|
||
根据查询结果可以看到,当我只用`insert`方法插入时的文档中是没有指定`_id`字段的,但`MongoDB`会为每条文档自动创建该字段作类似于主键的标识,且生成类型为`ObjectID`类型的值。
|
||
|
||
```shell
|
||
#查询articleid为”10000“的文档
|
||
> db.article.find({articleid:"100000"})
|
||
{ "_id" : ObjectId("5fed2b1b232584d8ba357db0"), "articleid" : "100000", "content" : "今天天气真好,阳光明 媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2020-12-31T01:36:27.784Z"), "likenum" : 10, "state" : null }
|
||
|
||
#投影查询,限定文档返回的字段(_id字段会默认显示)
|
||
> db.article.find({article:"100000"},{articleid:1})
|
||
{ "_id" : ObjectId("5fed2b1b232584d8ba357db0"), "articleid" : "100000" }
|
||
|
||
> db.article.find({articleid:"100000"},{articleid:1,_id:0})
|
||
{ "articleid" : "100000" }
|
||
|
||
#查询所有数据,只显示`_id`、`userid`、`nickname`
|
||
> db.article.find({},{userid:1,nickname:1})
|
||
```
|
||
|
||
|
||
|
||
#### 更新
|
||
|
||
文档的更新方法有:
|
||
|
||
- `db.collection.update()`
|
||
- `db.collection.updateOne()`
|
||
- `db.collection.updateMany()`
|
||
|
||
`update`方法的语法:
|
||
|
||
```shell
|
||
db.collection.update(query,update,option)
|
||
或
|
||
db.collection.update(
|
||
<query>,
|
||
<update>,
|
||
{
|
||
upsert: <boolean>,
|
||
multi: <boolean>,
|
||
writeConcern: <document>,
|
||
collation: <document>,
|
||
arrayFilters: [ <filterdocument1>, ... ],
|
||
hint: <document|string> // Available starting in MongoDB 4.2
|
||
}
|
||
)
|
||
```
|
||
|
||
参数列表
|
||
|
||
| Parameter | Type | Description |
|
||
| :------------- | :------------------- | :----------------------------------------------------------- |
|
||
| `query` | document | 更新条件,用于筛选出需要更新的文档。可以使用与`find`方法中相同的查询选择器,类似于`where`。在3.0版本中,当`upsert:true`执行`update`时。如果查询使用点表示法在`_id`字段上指定条件,则`MongoDB`将拒绝插入新的文档。 |
|
||
| `update` | document or pipeline | 要应用的修改。该值可以是:包含更新运算符表达式的文档,或仅包含:对的替换文档,或在MongoDB 4.2中启动聚合管道。管道可以由以下阶段组成: |
|
||
| `upsert` | boolean | 可选。如果设置为true,则在没有与查询条件匹配的文档时创建新文档。默认值为false,如果找不到匹配项,则不会插入新文档。 |
|
||
| `multi` | boolean | 可选。如果设置为true,则更新符合查询条件的多个文档。如果设置为false,则更新一个文档。默认值为false。 |
|
||
| `writeConcern` | document | 可选。表示写问题的文档。抛出异常的级别。 |
|
||
| `collation` | document | 可选。Collation允许用户为字符串比较指定特定于语言的规则,例如字母和重音标记的规则。 |
|
||
| `arrayFilters` | array | 可选的。筛选器文档的数组,用于确定要为对数组字段进行更新操作而修改哪些数组元素。 |
|
||
| `hint` | Document or string | 可选。指定用于支持查询谓词的索引的文档或字符串。该选项可以采用索引规范文档或索引名称字符串。如果指定的索引不存在,则说明操作错误。例如,请参阅版本4中的“为更新操作指定提示。 |
|
||
|
||
> 主要关注前四个参数即可
|
||
|
||
示例:
|
||
|
||
1. 覆盖的修改
|
||
|
||
将`_id`为1的记录,点赞数量为1001:
|
||
|
||
```shell
|
||
> db.article.update({_id:"1"},{likenum:NumberInt(1001)})
|
||
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
|
||
> db.article.find({_id:"1"})
|
||
{ "_id" : "1", "likenum" : 1001 }
|
||
```
|
||
|
||
结果是`update`文档将原文档覆盖替换了,其它字段没有了。
|
||
|
||
2. 局部修改
|
||
|
||
为了解决上面的问题,需要使用修改器`$set`来实现:
|
||
|
||
```shell
|
||
> db.article.update({_id:"2"},{$set:{likenum:NumberInt(666)}})
|
||
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
|
||
> db.article.find({_id:"2"})
|
||
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔 悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 666, "state" : "1" }
|
||
```
|
||
|
||
3. 批量修改
|
||
|
||
更改所有用户名为`1003`的用户的昵称为`小明`。
|
||
|
||
```shell
|
||
# 默认只修改第一个文档(记录)
|
||
> db.article.update({userid:"1003"},{$set:{nickname:"小明"}})
|
||
|
||
# 修改所有符合条件的数据
|
||
> db.article.update({userid:"1003"},{$set:{nickname:"小明"}},{multi:true})
|
||
```
|
||
|
||
4. 列值增长的修改
|
||
|
||
如果想实现对某列值在原有值的基础上进行增加或减少,可以使用`$inc`运算符来实现。
|
||
|
||
```shell
|
||
db.article.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})
|
||
```
|
||
|
||
|
||
|
||
#### 删除
|
||
|
||
删除文档的语法结构:
|
||
|
||
```shell
|
||
db.collection.remove(条件)
|
||
```
|
||
|
||
以下语句将会删除集合中全部的数据,慎用
|
||
|
||
```shell
|
||
db.collection.remove({})
|
||
```
|
||
|
||
|
||
|
||
#### 更多查询
|
||
|
||
1. `db.collection.count(query,options)`:统计查询
|
||
|
||
| Parameter | Type | Description |
|
||
| --------- | -------- | ---------------------------- |
|
||
| `query` | document | 查询条件 |
|
||
| `options` | document | 可选,用于修改计数的额外选项 |
|
||
|
||
```shell
|
||
#查询所有记录数
|
||
db.article.count()
|
||
|
||
#统计`userid`为1003的记录数
|
||
db.article.count({userid:"10003"})
|
||
```
|
||
|
||
2. `db.collection.find(<query>).limit(<number>)`:对`find`方法返回的`coursor`游标对象使用`limit`方法来指定返回文档的最大数量。默认为:20。
|
||
|
||
```shell
|
||
#返回查询结果的前两个文档
|
||
db.article.find().limit(2)
|
||
```
|
||
|
||
3. `db.collection.find(<query>).skip(<number>)`:在游标上调用skip()方法来控制`MongoDB`从哪里开始返回结果。这种方法在实现分页结果时可能很有用。
|
||
|
||
```shell
|
||
#返回除前三个文档的所有文档
|
||
db.article.find().skip(3)
|
||
|
||
#分页查询(第一页1,2,第二页3,4,第三页5)
|
||
#跳过前两条数据,取3,4,返回第二页
|
||
db.article.find().skip(2).limit(2)
|
||
```
|
||
|
||
4. `db.collection.find(<query>).sort({field: value})`:指定查询返回匹配文档的顺序。并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。
|
||
|
||
```shell
|
||
#对userid降序排列,并对访问量进行升序排列
|
||
db.article.find().sort({userid:-1,likenum:1})
|
||
```
|
||
|
||
> `skip()`, `limilt()`, `sort()`三个放在一起执行的时候,执行的顺序是先 `sort()`, 然后是 `skip()`,最后是显示的` limit()`,和命令编写顺序无关。
|
||
|
||
5. 模糊查询,`MongoDB`的模糊查询是通过**正则表达式**的方式实现的,格式为:
|
||
|
||
```shell
|
||
db.article.find({field:/正则表达式/})
|
||
|
||
#查询评论内容包含"开水"的所有文档
|
||
db.article.find({content:/开水/})
|
||
|
||
#查询评论内容以“专家”开头的数据
|
||
db.article.find({content:/^专家/})
|
||
```
|
||
|
||
> 正则表达式是JS的语法,直接量的写法
|
||
|
||
6. 比较查询
|
||
|
||
比较运算符对应的指令:
|
||
|
||
| 运算符 | 指令 |
|
||
| ------ | ------ |
|
||
| `<` | `$lt` |
|
||
| `<=` | `$lte` |
|
||
| `>` | `$gt` |
|
||
| `>=` | `$gte` |
|
||
| `!=` | `$ne` |
|
||
|
||
```shell
|
||
db.集合名称.find({"field":{$gt:value}}) //大于:field > value
|
||
db.集合名称.find({"field":{$gte:value}}) //大于等于:field >= value
|
||
db.集合名称.find({"field":{$lt:value}}) //小于:field < value
|
||
db.集合名称.find({"field":{$lte:value}}) //小于等于:field <= value
|
||
db.集合名称.find({"field":{$ne:value}}) //不等于:field != value
|
||
|
||
#查询评论点赞数量大于666的数据
|
||
db.article.find({likenum:{$gt:NumberInt(666)}})
|
||
```
|
||
|
||
7. 包含查询,使用`$in`指令
|
||
|
||
```shell
|
||
#查询userid包含1002、1003的文档
|
||
db.article.find({userid:{$in:["1003","1002"]}})
|
||
```
|
||
|
||
> 不包含使用`$nin`指令
|
||
|
||
8. 条件查询
|
||
|
||
与运算,查询同时满足两个以上的条件,需要使用`$and`指令将条件进行连接:
|
||
|
||
```shell
|
||
$and:[{},{},{}]
|
||
|
||
#查询评论集合中点赞数likenum大于等于666且小于2000的文档
|
||
db.article.find({$and:[{likenum:{$gte:NumberInt(666)}},{likenum:{$lt:NumberInt(2000)}}]},{likenum:1})
|
||
```
|
||
|
||
或运算,使用`$or`指令,格式与`$and`指令类似
|
||
|
||
```shell
|
||
$or:[{},{},{}]
|
||
```
|
||
|
||
### 常用命令小结
|
||
|
||
```shell
|
||
#选择切换数据库:
|
||
use articledb
|
||
|
||
#插入数据:
|
||
db.comment.insert({bson数据})
|
||
|
||
#查询所有数据:
|
||
db.comment.find();
|
||
|
||
#条件查询数据:
|
||
db.comment.find({条件})
|
||
|
||
#查询符合条件的第一条记录:
|
||
db.comment.findOne({条件})
|
||
|
||
#查询符合条件的前几条记录:
|
||
db.comment.find({条件}).limit(条数)
|
||
|
||
#查询符合条件的跳过的记录:
|
||
db.comment.find({条件}).skip(条数)
|
||
|
||
#修改数据:
|
||
db.comment.update({条件},{修改后的数据})
|
||
或
|
||
db.comment.update({条件},{$set:{要修改部分的字段:数据})
|
||
|
||
#修改数据并自增某字段值:
|
||
db.comment.update({条件},{$inc:{自增的字段:步进值}})
|
||
|
||
#删除数据:
|
||
db.comment.remove({条件})
|
||
|
||
#统计查询:
|
||
db.comment.count({条件})
|
||
|
||
#模糊查询:
|
||
db.comment.find({字段名:/正则表达式/})
|
||
|
||
#条件比较运算:
|
||
db.comment.find({字段名:{$gt:值}})
|
||
|
||
#包含查询:
|
||
db.comment.find({字段名:{$in:[值1,值2]}})
|
||
或
|
||
db.comment.find({字段名:{$nin:[值1,值2]}})
|
||
|
||
#条件连接查询:
|
||
db.comment.find({$and:[{条件1},{条件2}]})
|
||
或
|
||
db.comment.find({$or:[{条件1},{条件2}]})
|
||
```
|
||
|
||
|
||
|
||
## 四、索引(Index)
|
||
|
||
索引支持在`MongoDB`中高效地执行查询。如果没有索引,`MongoDB`必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
|
||
|
||
如果查询存在适当的索引,`MongoDB`可以使用该索引限制必须检查的文档数。
|
||
|
||
索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。**索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作**。此外,`MongoDB`还可以使用索引中的排序返回排序结果。
|
||
|
||
> `MongoDB`索引使用B树数据结构(确切的说是`B-Tree`,`MySQL`是`B+Tree`)
|
||
|
||
### 索引的类型
|
||
|
||
#### 单字段索引
|
||
|
||
`MongoDB`支持在文档的但个字段上创建用户定义的升序/降序索引,称为**单字段索引**(Single Field Index)。
|
||
|
||
对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为`MongoDB`可以在任何方向上遍历索引。
|
||
|
||

|
||
|
||
#### 复合索引
|
||
|
||
`MongoDB`还支持多个字段的用户定义索引,即**复合索引**(Compound Index)。
|
||
|
||
复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由`{userid:1,score:-1}`组成,则索引首先按`userid`正序排序,然后在每个`userid`的值内,再按`scroe`倒序排序。
|
||
|
||

|
||
|
||
|
||
|
||
#### 其他索引
|
||
|
||
- 地理空间索引(`Geospatial Index`):为了支持对地理空间坐标数据的有效查询,`MongoDB`提供了两种特殊的索引:返回结果时使用平面几何的**二维索引**和返回结果时使用球面几何的**二维球面索引**。
|
||
- 文本索引(Text Indexes):`MongoDB`提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如"the"、"a"、"or"),而将集合中的词作为词干,只存储根词。
|
||
- 哈希索引(Hash Indexes):为了支持基于散列的分片,`MongoDB`提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的分布更加随机,但只支持相等匹配,不支持基于范围的查询。
|
||
|
||
|
||
|
||
### 索引的管理
|
||
|
||
- `db.collection.getIndexes()`:**查看**集合中所有索引的数组。该命令运行要求是`MongoDB 3.0+`。
|
||
|
||
```shell
|
||
> db.article.getIndexes()
|
||
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
|
||
```
|
||
|
||
结果中显示的是默认`_id`索引。主键默认会创建唯一值索引。
|
||
|
||
`v`代表的是索引引擎的版本号。`key`表示加了索引的字段`_id`,值`1`表示升序。`name`表示索引的名称,默认的方式是索引字段名称后面加下划线。`ns`表示命名空间,通常是数据库+集合名称。
|
||
|
||
> `MongoDB`在创建集合的过程中,在`_id`字段上创建一个唯一的索引,默认名字为`_id_`,该索引可防止客户端插入两个具有相同值的文档,不能再`_id`字段上删除此索引。
|
||
>
|
||
> 该索引是唯一索引,因此值不能重复,即`_id`值不能重复,在分片集群中通常使用`_id`作为片键。
|
||
|
||
- `db.collection.createIndex(keys,options)`:在集合上**创建**索引
|
||
|
||
参数
|
||
|
||
| param | type | description |
|
||
| --------- | -------- | ------------------------------------------------------------ |
|
||
| `keys` | document | 包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段上的升序索引,请指定值1;对于降序索引,请指定值-1。比如: {字段:1或-1} ,其中1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。另外,MongoDB支持几种不同的索引类型,包括文本、地理空间和哈希索引。 |
|
||
| `options` | document | 可选。包含一组控制索引创建的选项的文档。有关详细信息,请参见选项详情列表。 |
|
||
|
||
常用`options`选项:
|
||
|
||
| param | type | description |
|
||
| ---------- | -------- | ------------------------------------------------------------ |
|
||
| background | boolean | 建索引过程会阻塞其它数据库操作,background可以指定以后台方式创建索引,默认为false |
|
||
| unique | boolean | 建立的索引是否唯一,指定为true创建唯一索引,默认为false |
|
||
| name | string | 索引名称。 |
|
||
| weights | document | 索引的权重,数值在1到99999之间,表示该索引相对其他索引字段的得分权重 |
|
||
|
||
> 在 3.0.0 版本前创建索引方法为 `db.collection.ensureIndex() `,之后的版本使用了 `db.collection.createIndex()` 方法,`ensureIndex() `还能用,但只是 `createIndex()` 的别名。
|
||
|
||
示例:
|
||
|
||
```shell
|
||
> db.article.getIndexes()
|
||
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
|
||
|
||
#单字段索引,对userid字段按升序建立索引
|
||
> db.article.createIndex({userid:1})
|
||
{
|
||
"createdCollectionAutomatically" : false,
|
||
"numIndexesBefore" : 1,
|
||
"numIndexesAfter" : 2,
|
||
"ok" : 1
|
||
}
|
||
|
||
#复合索引,对userid字段升序和nickname字段降序建立符合索引
|
||
> db.article.createIndex({userid:1,nickname:-1})
|
||
{
|
||
"createdCollectionAutomatically" : false,
|
||
"numIndexesBefore" : 2,
|
||
"numIndexesAfter" : 3,
|
||
"ok" : 1
|
||
}
|
||
> db.article.getIndexes()
|
||
[
|
||
{
|
||
"v" : 2,
|
||
"key" : {
|
||
"_id" : 1
|
||
},
|
||
"name" : "_id_"
|
||
},
|
||
{
|
||
"v" : 2,
|
||
"key" : {
|
||
"userid" : 1
|
||
},
|
||
"name" : "userid_1"
|
||
},
|
||
{
|
||
"v" : 2,
|
||
"key" : {
|
||
"userid" : 1,
|
||
"nickname" : -1
|
||
},
|
||
"name" : "userid_1_nickname_-1"
|
||
}
|
||
]
|
||
```
|
||
|
||
- `db.collection.dropIndex(index)`:移除指定索引
|
||
|
||
| param | type | description |
|
||
| ----- | ------------------ | ------------------------------------------------------------ |
|
||
| index | string or document | 指定要删除的索引。可以通过索引名称或索引规则文档指定索引,若删除文本索引,请指定索引名称。 |
|
||
|
||
示例:
|
||
|
||
```shell
|
||
> db.article.dropIndex("userid_1")
|
||
{ "nIndexesWas" : 3, "ok" : 1 }
|
||
> db.article.getIndexes()
|
||
[
|
||
{
|
||
"v" : 2,
|
||
"key" : {
|
||
"_id" : 1
|
||
},
|
||
"name" : "_id_"
|
||
},
|
||
{
|
||
"v" : 2,
|
||
"key" : {
|
||
"userid" : 1,
|
||
"nickname" : -1
|
||
},
|
||
"name" : "userid_1_nickname_-1"
|
||
}
|
||
]
|
||
```
|
||
|
||
- `db.collection.dropIndexes()`:移除集合中所有索引(除了默认`_id_`索引)
|
||
|
||
```shell
|
||
> db.article.dropIndexes()
|
||
{
|
||
"nIndexesWas" : 2,
|
||
"msg" : "non-_id indexes dropped for collection",
|
||
"ok" : 1
|
||
}
|
||
> db.article.getIndexes()
|
||
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
|
||
```
|
||
|
||
|
||
|
||
### 索引的使用
|
||
|
||
#### 执行计划
|
||
|
||
分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间,是否基于索引查询等。
|
||
|
||
应用场景:查看建立的索引是否有效?效率如何?
|
||
|
||
语法:`db.collection.find(query,option).explain(options)`
|
||
|
||
示例:
|
||
|
||
```shell
|
||
> db.article.find({userid:"1003"}).explain()
|
||
{
|
||
"queryPlanner" : {
|
||
"plannerVersion" : 1,
|
||
"namespace" : "meface.article",
|
||
"indexFilterSet" : false,
|
||
"parsedQuery" : {
|
||
"userid" : {
|
||
"$eq" : "1003"
|
||
}
|
||
},
|
||
"queryHash" : "37A12FC3",
|
||
"planCacheKey" : "37A12FC3",
|
||
"winningPlan" : {
|
||
"stage" : "COLLSCAN",
|
||
"filter" : {
|
||
"userid" : {
|
||
"$eq" : "1003"
|
||
}
|
||
},
|
||
"direction" : "forward"
|
||
},
|
||
"rejectedPlans" : [ ]
|
||
},
|
||
"serverInfo" : {
|
||
"host" : "u20",
|
||
"port" : 27017,
|
||
"version" : "4.4.2",
|
||
"gitVersion" : "15e73dc5738d2278b688f8929aee605fe4279b0e"
|
||
},
|
||
"ok" : 1
|
||
}
|
||
```
|
||
|
||
可以看到`winningPlan`中的`stage`是`COLLSCAN`(集合扫描),说明没有使用索引。
|
||
|
||
下面创建`userid`索引,再执行计划:
|
||
|
||
```shell
|
||
> db.article.createIndex({userid:1})
|
||
{
|
||
"createdCollectionAutomatically" : false,
|
||
"numIndexesBefore" : 1,
|
||
"numIndexesAfter" : 2,
|
||
"ok" : 1
|
||
}
|
||
> db.article.find({userid:"1003"}).explain()
|
||
{
|
||
"queryPlanner" : {
|
||
"plannerVersion" : 1,
|
||
"namespace" : "meface.article",
|
||
"indexFilterSet" : false,
|
||
"parsedQuery" : {
|
||
"userid" : {
|
||
"$eq" : "1003"
|
||
}
|
||
},
|
||
"queryHash" : "37A12FC3",
|
||
"planCacheKey" : "7FDF74EC",
|
||
"winningPlan" : {
|
||
"stage" : "FETCH",
|
||
"inputStage" : {
|
||
"stage" : "IXSCAN",
|
||
"keyPattern" : {
|
||
"userid" : 1
|
||
},
|
||
"indexName" : "userid_1",
|
||
"isMultiKey" : false,
|
||
"multiKeyPaths" : {
|
||
"userid" : [ ]
|
||
},
|
||
"isUnique" : false,
|
||
"isSparse" : false,
|
||
"isPartial" : false,
|
||
"indexVersion" : 2,
|
||
"direction" : "forward",
|
||
"indexBounds" : {
|
||
"userid" : [
|
||
"[\"1003\", \"1003\"]"
|
||
]
|
||
}
|
||
}
|
||
},
|
||
"rejectedPlans" : [ ]
|
||
},
|
||
"serverInfo" : {
|
||
"host" : "u20",
|
||
"port" : 27017,
|
||
"version" : "4.4.2",
|
||
"gitVersion" : "15e73dc5738d2278b688f8929aee605fe4279b0e"
|
||
},
|
||
"ok" : 1
|
||
}
|
||
```
|
||
|
||
可以看到`stage`是`IXSCAN`,基于索引的扫描。
|
||
|
||
在可视化工具`compass`中,可以更加清除的查看到。先从索引集合中扫描,抓取匹配的文档。
|
||
|
||

|
||
|
||
|
||
|
||
#### 涵盖查询
|
||
|
||
涵盖查询(Covered Queries):当查询条件和查询的投影仅包含索引字段时,`MongoDB`直接从索引返回结果,而不扫描任何文档或将文档带入内存。这些覆盖的查询可以非常的有效。
|
||
|
||

|
||
|
||
示例:
|
||
|
||
```shell
|
||
> db.article.find({userid:"1003"},{userid:1,_id:0})
|
||
{ "userid" : "1003" }
|
||
{ "userid" : "1003" }
|
||
> db.article.find({userid:"1003"},{userid:1,_id:0}).explain()
|
||
{
|
||
"queryPlanner" : {
|
||
"plannerVersion" : 1,
|
||
"namespace" : "meface.article",
|
||
"indexFilterSet" : false,
|
||
"parsedQuery" : {
|
||
"userid" : {
|
||
"$eq" : "1003"
|
||
}
|
||
},
|
||
"queryHash" : "8177476D",
|
||
"planCacheKey" : "B632EADC",
|
||
"winningPlan" : {
|
||
"stage" : "PROJECTION_COVERED",
|
||
"transformBy" : {
|
||
"userid" : 1,
|
||
"_id" : 0
|
||
},
|
||
"inputStage" : {
|
||
"stage" : "IXSCAN",
|
||
"keyPattern" : {
|
||
"userid" : 1
|
||
},
|
||
"indexName" : "userid_1",
|
||
"isMultiKey" : false,
|
||
"multiKeyPaths" : {
|
||
"userid" : [ ]
|
||
},
|
||
"isUnique" : false,
|
||
"isSparse" : false,
|
||
"isPartial" : false,
|
||
"indexVersion" : 2,
|
||
"direction" : "forward",
|
||
"indexBounds" : {
|
||
"userid" : [
|
||
"[\"1003\", \"1003\"]"
|
||
]
|
||
}
|
||
}
|
||
},
|
||
"rejectedPlans" : [ ]
|
||
},
|
||
"serverInfo" : {
|
||
"host" : "u20",
|
||
"port" : 27017,
|
||
"version" : "4.4.2",
|
||
"gitVersion" : "15e73dc5738d2278b688f8929aee605fe4279b0e"
|
||
},
|
||
"ok" : 1
|
||
}
|
||
```
|
||
|
||
在`compass`工具中查看,`Query covered by index`只查询了索引的集合。
|
||
|
||

|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
## 参考文档
|
||
|
||
[1] `Collection Methods`https://docs.mongodb.com/manual/reference/method/js-collection/
|
||
|
||
[2] `Cursor Methods` https://docs.mongodb.com/manual/reference/method/js-cursor/
|
||
|
||
[3] `MongoDB CRUD Operations` https://docs.mongodb.com/manual/crud/
|
||
|
||
[4] `Indexes` https://docs.mongodb.com/manual/indexes/
|
||
|
||
[5] `MongoDB基础入门到高级进阶` https://www.bilibili.com/video/BV1j541187bA
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|