# MongoDB 知识总结
# 一、基本介绍
官方文档:https://docs.mongodb.com/
中文文档:https://www.mongodb.org.cn/
操作文档:https://www.qikegu.com/docs/3283
MongoDB 是由 C++ 语言编写并基于分布式文件存储的开源数据库,属于 NOSQL 。
MongoDB 是一款介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的 NOSQL 数据库。它面向文档存储,而且安装和操作起来都比较简单和容易,而且它支持各种流行编程语言进行操作,如 Python,Node.js,Java,C++,PHP,C# 等。
目前在大数据、内容管理、持续交付、移动应用、社交应用、用户数据管理、数据中心等领域皆有广泛被使用。
# 1.1 MongoDB 相对于 RDBMS 的优势
-
无固定结构 。
-
数据结构由键值 (key=>value) 对组成。MongoDB 的文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组,单个对象的结构是清晰的。
-
没有复杂的表连接。不需要维护表与表之间的内在关联关系。
-
查询功能强大。MongoDB 的查询功能几乎与 SQL 一样强大,使用基于文档的查询语言,可以对文档进行动态查询。
-
易于调优和扩展。具备高性能、高可用性及可伸缩性等特性
-
应用程序对象与数据库对象天然对应。
-
可以基于内存存储或者硬盘文件存储,提供丰富的查询操作和索引支持,也有事务操作,可以更快地更稳定的访问数据。
# 1.2 术语对比
SQL | Mongodb | 描述 |
---|---|---|
库(database) | 库(database) | |
表(Table) | 集合(Collection) | |
行 / 记录(Row) | 文档(Document) | Document 就是 json 结构的一条数据记录 |
列 / 字段(Col) | 字段 / 键 / 域(Field) | |
主键(Primary Key) | 对象 ID(ObjectId) | _id: ObjectId(“10c191e8608f19729507deea”) |
索引(Index) | 索引(Index) | 也有普通索引,唯一索引这么区分的 |
# 1.3 基本安装及用法
目前最新版本为 4.4 版本,ubuntu18.04 中默认安装的是 3.6 版本【可以继续基于这个版本进行学习,这块内容跳过即可】。
安装之前建议更新下 Linux 源.
# 1、备份源文件 | |
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak | |
# 2、添加源到 sources.list 中 | |
sudo gedit /etc/apt/sources.list | |
# 在打开的文本中,添加阿里源 | |
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse | |
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse | |
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse | |
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse | |
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse | |
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse | |
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse | |
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse | |
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse | |
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse | |
# 3、更新源 | |
sudo apt-get update |
如果要在 ubuntu18.04 中安装最新 4.4 版本 mongodb,则需要完成以下命令步骤:
# 安装依赖包 | |
sudo apt-get install libcurl4 openssl | |
# 关闭和卸载原有的 mongodb | |
service mongodb stop | |
sudo apt-get remove mongodb | |
# 导入包管理系统使用的公钥 | |
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - | |
# 如果命令执行结果没有显示 OK,则执行此命令在把上一句重新执行:sudo apt-get install gnupg | |
# 注册 mongodb 源 | |
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list | |
# 更新源 | |
sudo apt-get update | |
# 安装 mongodb | |
sudo apt-get install -y mongodb-org=4.4.2 mongodb-org-server=4.4.2 mongodb-org-shell=4.4.2 mongodb-org-mongos=4.4.2 mongodb-org-tools=4.4.2 | |
# 安装过程中如果提示: mongodb-org-tools : 依赖: mongodb-database-tools 但是它将不会被安装 | |
# 终端下运行以下命令,解决: | |
# sudo apt-get autoremove mongodb-org-mongos mongodb-org-tools mongodb-org | |
# sudo apt-get install -y mongodb-org=4.4.2 | |
# 创建数据存储目录 | |
sudo mkdir -p /data/db | |
# 修改配置,开放 27017 端口 | |
sudo vim /etc/mongod.conf | |
# 把 12 行附近的 port=27017 左边的 #号去掉 |
启动和关闭 MongoDB
# 重新加载配置,并启动 mongodb | |
sudo systemctl daemon-reload | |
sudo systemctl start mongod | |
# 查看运行状态 | |
sudo systemctl status mongod | |
# 如果 mongodb 状态为 stop,则运行 sudo systemctl enable mongod | |
# 停止 mongodb | |
sudo systemctl stop mongod | |
# 重启 mongodb | |
sudo systemctl restart mongod |
进入交互终端
MongoDB 安装完成后,默认是没有权限验证的,默认是不需要输入用户名密码即可登录的
也可以启动权限认证,但是必须注意:
mongodb 默认是没有管理员账号的,所以要先切换到 admin 数据库添加管理员账号,再开启权限认证,否则就玩大了。
# 进入交互终端 | |
mongo |
效果:
MongoDB shell version v4.4.2 | |
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb | |
Implicit session: session { "id" : UUID("2c920d56-ddbb-4649-9191-a3bd4506a2d2") } | |
MongoDB server version: 4.4.2 | |
--- | |
The server generated these startup warnings when booting: | |
# 警告:强烈建议使用 XFS 文件系统,并使用 WiredTiger 存储引擎。 | |
# 解释:因为当前 ubuntu 使用的是 ext4 文件系统,mongodb 官方建议使用 XFS 文件系统功能更能发挥 mongodb 的性能,忽略不管 | |
2020-11-23T16:23:34.416+08:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem | |
# 警告:当前 mongodb 没有为数据库启用访问控制。对数据和配置的读写访问是不受限制的。 | |
# 解释:后面会创建数据库用户采用密码登陆的。暂时不用管 | |
2020-11-23T16:23:35.046+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted |
mongod 是处理 MongoDB 系统的主要进程。主要负责处理数据请求,管理数据存储,和执行后台管理操作。
当我们运行 mongod 命令意味着正在启动 MongoDB 进程,并且在后台运行。
mongo 是一个命令行工具,用于连接一个特定的 mongod 实例。
当我们没有带参数运行 mongo 命令它将使用默认的端口号 27017 和 localhost 进行连接
退出交互终端
exit | |
# quit() |
查看版本
mongo --version | |
# 或者终端内部使用 version () |
# 二、通用操作
# 2.1 查看帮助文档
- help
db.help() help on db methods | |
db.mycoll.help() help on collection methods | |
sh.help() sharding helpers 分片 | |
rs.help() replica set helpers 复制集 | |
help admin administrative help | |
help connect connecting to a db help | |
help keys key shortcuts | |
help misc misc things to know | |
help mr mapreduce | |
show dbs show database names | |
show collections show collections in current database | |
show users show users in current database | |
show profile show most recent system.profile entries with time >= 1ms | |
show logs show the accessible logger names | |
show log [name] prints out the last segment of log in memory, 'global' is default | |
use <db_name> set current database | |
db.mycoll.find() list objects in collection mycoll | |
db.mycoll.find( { a : 1 } ) list objects in mycoll where a == 1 | |
it result of the last line evaluated; use to further iterate | |
DBQuery.shellBatchSize = x set default number of items to display on shell | |
exit quit the mongo shell |
# 2.2 当前服务器状态
- db.serverStatus()
{ | |
"host" : "ubuntu", # 主机名 | |
"version" : "4.4.2", # mongodb版本 | |
"process" : "mongod", # mongodb进程,主要有mongod和mongos(分片集群中)两种 | |
"pid" : NumberLong(1034), # mongod的pid进程号,可以在linux终端下使用命令 pidof mongod 验证 | |
"uptime" : 105063, # mongod服务启动的秒数 | |
"uptimeMillis" : NumberLong(105063193), # mongod服务启动的毫秒数 | |
"uptimeEstimate" : NumberLong(105063), # mongod内部自己计算的启动秒数 | |
"localTime" : ISODate("2020-12-08T16:01:08.230Z"), # 本地时间,相当于 python的 datetime | |
# 连接数相关 | |
"connections" : { | |
"current" : 1, # 当前连接数 | |
"available" : 51199, # 可用连接数 | |
"totalCreated" : 1, # 截止目前为止总共创建的连接数 | |
"active" : 1, # 还在活跃的连接数 | |
}, | |
"globalLock" : { # 全局锁相关信息 | |
"totalTime" : NumberLong("105063115000"), # mongod启动后到现在的总时间,单位微秒 | |
"currentQueue" : { # 当前等待锁队列 | |
"total" : 0, # 当前全局锁的等待个数 | |
"readers" : 0, # 当前全局读锁等待个数 | |
"writers" : 0 # 当前全局写锁等待个数 | |
}, | |
"activeClients" : { | |
"total" : 0, # 当前活跃客户端的个数 | |
"readers" : 0, # 当前活跃客户端中进行读操作的个数 | |
"writers" : 0 # 当前活跃客户端中进行写操作的个数 | |
} | |
}, | |
"network" : { # 网络相关 | |
"bytesIn" : NumberLong(1611), # 数据库接收到的网络传输字节数 | |
"bytesOut" : NumberLong(51269), # 从数据库发送出去的网络传输字节数 | |
"numRequests" : NumberLong(16), # mongod接收到的总请求次数 | |
}, | |
# 操作计数器 | |
"opcounters" : { | |
"insert" : NumberLong(0), # 本次mongod实例启动至今收到的插入操作总数 | |
"query" : NumberLong(287), # 本次mongod实例启动至今收到的查询总数。 | |
"update" : NumberLong(0), # 本次mongod实例启动至今收到的更新操作总数 。 | |
"delete" : NumberLong(0), # 本次mongod实例启动至今的删除操作总数。 | |
"getmore" : NumberLong(0), # 本次mongod实例启动至今“getmore”操作的总数。 | |
"command" : NumberLong(588)# 本次mongod实例启动至今向数据库发出的命令总数 。 | |
}, | |
# 存储引擎,是MongoDB的核心组件,负责管理数据如何存储在硬盘(Disk)和内存(Memory)上 | |
# MongoDB 支持多种不同的存储引擎(Storage Engine),MongoDB支持的存储引擎有:WiredTiger,MMAPv1和In-Memory。 | |
# 1. WiredTiger,将数据持久化存储在硬盘文件中;从MongoDB 3.2 版本开始,成为MongDB默认存储引擎 | |
# 2. In-Memory,将数据存储在内存中 | |
# 3. MMAPv1,将数据持久化存储在硬盘文件中; | |
# WiredTiger是比MMAPv1更好用,更强大的存储引擎,WiredTiger的写操作会先写入缓存(Cache)中,并持久化到WAL(Write ahead log,写日志),每60s或日志文件达到2GB时会做一次Checkpoint(检查点),将当前数据进行持久化,产生一个新的快照。Wiredtiger连接初始化时,首先将数据恢复至最新的快照状态,然后根据WAL恢复数据,以保证存储可靠性。 | |
# Checkpoint,检测点。将内存中的数据变更冲刷到磁盘中的数据文件中,并做一个标记点。 | |
# 表示此前的数据表示已经持久存储在了数据文件中,此后的数据变更存在于内存和日志中. | |
# 是一种让数据库redo(重做)和data(数据)文件保持一致的机制。 | |
# 并非Mongodb独有的,mysql中的InnoDB也有。 | |
"storageEngine" : { | |
"name" : "wiredTiger", | |
"supportsCommittedReads" : true, | |
"oldestRequiredTimestampForCrashRecovery" : Timestamp(0, 0), | |
"supportsPendingDrops" : true, | |
"dropPendingIdents" : NumberLong(0), | |
"supportsTwoPhaseIndexBuild" : true, | |
"supportsSnapshotReadConcern" : true, | |
"readOnly" : false, | |
"persistent" : true, | |
"backupCursorOpen" : false | |
}, | |
"transactions" : { # 事务,mongodb4.0以后新增特性 | |
"retriedCommandsCount" : NumberLong(0), | |
"retriedStatementsCount" : NumberLong(0), | |
"transactionsCollectionWriteCount" : NumberLong(0), | |
"currentActive" : NumberLong(0), | |
"currentInactive" : NumberLong(0), | |
"currentOpen" : NumberLong(0), | |
"totalAborted" : NumberLong(0), | |
"totalCommitted" : NumberLong(0), | |
"totalStarted" : NumberLong(0), | |
"totalPrepared" : NumberLong(0), | |
"totalPreparedThenCommitted" : NumberLong(0), | |
"totalPreparedThenAborted" : NumberLong(0), | |
"currentPrepared" : NumberLong(0) | |
}, | |
"locks":{ # 锁相关 | |
}, | |
"mem" : { # 内存相关 | |
"bits" : 64, # 操作系统位数 | |
"resident" : 18, # 物理内存消耗,单位:M | |
"virtual" : 1566, # 虚拟内存消耗 | |
"supported" : true # 是否显示额外的内存信息 | |
}, | |
} |
# 2.3 查看当前 db 的连接机器地址
- db.getMongo()
# 2.4 查看日志
- show logs
show logs | |
# global | |
# startupWarnings | |
# 如果要查看具体文件的日志。 | |
show log global |
# 2.5 数据备份与恢复
MongdoDB 一共提供了 4 个命令工具给我们对数据进行备份与恢复以及导入与导出数据。
- 数据备份
mongodump -h dbhost -d dbname -o dbdirectory |
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-h | MongoDB 服务端地址和端口的简写 | –host=MongoDB 地址 --port = 端口 |
-d | 备份的数据库名称 | –db = 数据库名称 |
-o | 备份数据保存目录 | 目录需要提前创建 |
- 数据恢复
mongorestore -h dbhost -d dbname --dir dbdirectory |
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-h | MongoDB 服务端地址和端口的简写 | –host=MongoDB 地址 --port = 端口 |
-d | 备份的数据库名称 | –db = 数据库名称 |
–dir | 备份数据所在目录 | |
–drop | 恢复数据前,先删除 MongoDB 中的数据 |
- 数据导出
mongoexport -d dbname -c collectionname -o file --type json/csv -f field |
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-d | 要导出的数据库名称 | –db = 数据库名称 |
-c | 要导出的集合名称 | –collection = 集合名称 |
-o | 导出数据保存的文件名 | |
–type | 导出数据的文件格式 | 默认是 json,也可以是 csv,当数据格式为 csv 时,另需加上 - f “字段 1, 字段 2,…” |
- 数据导入
mongoimport -d dbname -c collectionname --file filename --headerline --type json/csv -f field |
参数说明:
选项 | 作用 | 备注 |
---|---|---|
-d | 要导入的数据库名称 | –db = 数据库名称 |
-c | 要导入的集合名称 | –collection = 集合名称 |
–file | 导入数据保存的文件名 | |
–type | 导入数据的文件格式 | 默认是 json, 也可以是 csv,当数据格式为 csv 时: 1. 需加上 - f “字段 1, 字段 2,…” 2. 可以选择加上–headerline,设置首行为导入字段 |
# 三、用户管理
# 3.1 创建用户
db.createUser(user, writeConcern) |
创建一个数据库新用户用 db.createUser () 方法,如果用户存在则返回一个用户重复错误。
错误信息: uncaught exception: Error: couldn't add user: User "用户名@数据库" already exists
语法:
{ | |
user: "<用户名>", | |
pwd: "<密码>", | |
customData: { <any information> }, # 任意内容,主要是为了表示用户身份的相关介绍 | |
roles: [ # 角色和权限分配 | |
{ role: "<role>", db: "<database>" }, # 也可以直接填写由mongoDB内置的角色,例如: "<role>" | |
... | |
] | |
} |
mongo 的用户是以数据库为单位来建立的,每个数据库有自己的管理员。
管理员可以管理自己的数据库,但是不能直接管理其他数据库,要先在 admin 数据库认证后才可以。
管理员的权限设置包含了 2 块,分别是角色和权限,由 roles 属性进行设置。
内置角色:
数据库用户角色:read、readWrite; | |
数据库管理角色:dbAdmin、dbOwner、userAdmin; | |
集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager; | |
备份恢复角色:backup、restore; | |
所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase | |
超级用户角色:root | |
# 有几个角色间接或直接提供了系统超级用户的访问权限(dbOwner 、userAdmin、userAdminAnyDatabase) |
内置权限:
Read:允许用户读取指定数据库 | |
readWrite:允许用户读写指定数据库 | |
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile | |
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户 | |
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。 | |
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限 | |
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限 | |
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限 | |
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。 | |
root:只在admin数据库中可用。超级账号,擁有超级权限 |
给 Admin 数据库创建账户管理员(相当于 hr)
当前账号只能用于管理 admin 数据库账号,不能进行其他数据库的操作
# 进入/切换数据库到admin中 | |
use admin; | |
# 创建账户管理员 | |
db.createUser({ | |
user: "oldboy", | |
pwd: "123456", | |
roles: [ | |
{role: "userAdminAnyDatabase",db:"admin"}, | |
] | |
}); | |
# 终端效果如下: | |
Successfully added user: { | |
"user" : "oldboy", | |
"roles" : [ | |
{ | |
"role" : "userAdminAnyDatabase", | |
"db" : "admin" | |
} | |
] | |
} |
创建超级管理员
当前账号可以进行数据库相关操作。
# 进入/切换数据库到admin中 | |
use admin | |
# 创建超级管理员账号 | |
db.createUser({ | |
user: "super", | |
pwd: "123456", | |
roles: [ | |
"root", # 也可以这样写 {role:"root", db:"admin"} | |
] | |
}); | |
db.createUser({ | |
user: "python", | |
pwd: "123456", | |
roles: [ | |
{role:"root", db:"admin"}, | |
] | |
}) |
创建用户自己的数据库的角色
帐号是跟着数据库绑定的,所以是什么数据库的用户,就必须在指定库里授权和验证!!!
# 切换数据库,如果当前库不存在则自动创建 | |
use mofang | |
# 创建管理员用户,为了保证不会报错,所以先删除同名管理员 db.system.users.remove({user:"mofang"}); | |
db.createUser({ | |
user: "mofang", | |
pwd: "123", | |
roles: [ | |
{ role: "dbOwner", db: "mofang"} | |
] | |
}) |
# 3.2 用户信息
查看当前数据库下的管理用户
只需要切换到对应的库中即可查看
use mofang | |
show users |
查看系统中所有的用户
需要切换到 admin 中使用账号管理员的权限进行操作
use admin | |
db.auth("root","123456") | |
db.system.users.find() # 只能在 admin 数据库中使用。 |
# 3.3 删除用户
db.system.users.remove(json条件) |
要切换到 admin 用户中
# 有多种删除方式,下面是根据 user 用户名删除用户 | |
db.system.users.remove({user:"mofang"}); | |
# 删除效果: | |
WriteResult({ "nRemoved" : 1 }) # nRemoved 大于 0 表示成功删除管理员,等于 0 则表示没有删除。 |
# 3.4 修改信息
修改密码
必须切换到对应的数据库下
db.changeUserPassword (“账户名”, “新密码”)
use mofang | |
# 注册必须保证有这个管理员 | |
db.changeUserPassword("mofang", "123456") |
# 3.5 开启 mongodb 账户认证机制
sudo vim /etc/mongod.conf | |
# 找到 31 行附近的 security,去掉左边注释符号 (#) | |
security: | |
authorization: enabled | |
:wq | |
# 重启 mongdb,配置生效 | |
sudo systemctl restart mongod | |
# 开启了账户认证机制以后,再次进入 mofang | |
mongo | |
use mofang | |
show users # 此处会报错如:uncaught exception: Error: command usersInfo requires authentication | |
db.auth("mofang","123") # 此处认证时填写错误密码,报错如下: | |
# Error: Authentication failed. | |
# 0 | |
db.auth("mofang","123456") # 此处认证时填写正确密码,效果如下: | |
# 1 | |
show users # 此时经过认证以后,当前命令就不会被限制了。 |
注意:
如果上面重启以后,认证机制不生效,则执行如下代码:
sudo pkill mongod # 杀死 mongod 服务 | |
sudo mongod -f /etc/mongod.conf --fork --auth # --auth 表示以认证模式启动服务,不加则关闭 |
# 四、库管理
- 显示所有数据库列表【空数据库不会显示,或者说空数据库已经被 mongoDB 回收了。
show dbs | |
show databases |
- 切换数据库,如果数据库不存在则创建数据库。
use <database> |
- 查看当前工作的数据库
db | |
db.getName() |
- 删除当前数据库,如果数据库不存在,也会返回
{"ok":1}
db.dropDatabase() |
- 查看当前数据库状态
> db.stats() | |
{ | |
"db" : "mofang", | |
"collections" : 0, | |
"views" : 0, | |
"objects" : 0, | |
"avgObjSize" : 0, | |
"dataSize" : 0, | |
"storageSize" : 0, | |
"totalSize" : 0, | |
"indexes" : 0, | |
"indexSize" : 0, | |
"scaleFactor" : 1, | |
"fileSize" : 0, | |
"fsUsedSize" : 0, | |
"fsTotalSize" : 0, | |
"ok" : 1 | |
} |
# 五、集合管理
# 5.1 创建集合
在 mongodb 中其实不需要专门创建集合,直接添加文档,mongodb 也会自动生成集合的。
name为必填参数,options为可选参数。capped若设置值为true,则size必须也一并设置 | |
db.createCollection( | |
name=<集合名称>, | |
options = { | |
capped : <boolean>, # 创建固定集合,固定集合指限制固定数据大小的集合,当数据达到最大值会自动覆盖最早的文档内容 | |
size : <bytes_size>, # 指定固定集合存储的最大字节数,单位:字节数. | |
max : <collection_size> # 指定固定集合中包含文档的最大数量,单位:字节数 | |
}); | |
# 添加文档到不存在的集合中,mongodb会自动创建集合, | |
db.集合.insert({"name":"python入门","price" : 31.4}) |
# 5.2 集合列表
show collections # 或 show tables 或 db.getCollectionNames () |
# 5.3 删除集合
db.集合.drop() |
# 5.4 查看集合
db.getCollection("集合") | |
db.集合 |
效果:
MongoDB Enterprise > db.user_list | |
mofang.user_list |
查看集合创建信息
db.printCollectionStats() |
# 六、文档管理
# 6.1 数据类型
Type | 描述 |
---|---|
ObjectID | 用于存储文档的 ID, 相当于主键,mongoDB 中就是一个对象的返回值 |
String | 字符串是最常用的数据类型,MongoDB 中的字符串必须是 UTF-8 编码。 |
Integer | 整数类型用于存储数值。整数可以是 32 位,也可以是 64 位,这取决于你的服务器。 |
Double | 双精度类型用于存储浮点值,mongodb 中没有 float 浮点数这个说法 |
Boolean | 布尔类型用于存储布尔值 (true/false) |
Arrays | 将数组、列表或多个值存储到一个键 |
Timestamp | 时间戳,用于记录文档何时被修改或创建。Date (),Timestamp (),ISODate () |
Object | 用于嵌入文档,相当于子属性是另一个 json 而已 |
Null | 空值,相当于 python 的 None |
Symbol | 与字符串用法相同,常用于某些使用特殊符号的语言 |
Date | 用于以 UNIX 时间格式存储当前日期或时间。 |
Binary data | 二进制数据 |
Code | 用于将 JavaScript 代码存储到文档中 |
Regular expression | 正则表达式 |
# 6.2 添加文档
文档的数据结构和 JSON 基本一样。所有存储在集合中的数据都是 BSON 格式。
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。
# 添加文档 | |
# 方式 1: | |
db.集合.insert(<document>) # document 就是一个 json | |
# 方式 2: | |
db.集合.insertOne( # 如果文档存在_id 主键为更新数据,否则就添加数据。 | |
<document> | |
) | |
# 方式 3 | |
# 一次性添加多个文档,多次给同一个集合建议使用 insertMany 比 insertOne 效率更好 | |
db.集合.insertMany( | |
[ <document> , <document>, ... ] | |
) |
操作:
use mofang; | |
// 添加一条数据 | |
db.user_list.insert({"name":"laoli","age":33,"sex":true,"child":{"name":"xiaohuihui","age":3}}); | |
// WriteResult({ "nInserted" : 1 }) | |
// 添加一条数据 | |
db.user_list.insertOne({"name":"xiaozhang","age":18,"sex":true}); | |
// { | |
// "acknowledged" : true, | |
// "insertedId" : ObjectId("605021e6d5c7a55cc95c1cb7") | |
// } | |
// 添加多条数据 | |
document1 = {"name":"xiaolan","age":16} | |
document2 = {"name":"xiaoguang","age":16} | |
db.user_list.insertMany([document1,document2]); | |
// { | |
// "acknowledged" : true, | |
// "insertedIds" : [ | |
// ObjectId("60502235d5c7a55cc95c1cba"), | |
// ObjectId("60502235d5c7a55cc95c1cbb") | |
// ] | |
// } |
# 6.3 删除文档
db.集合.remove( | |
<query>, // removed的条件,一般写法:{"属性":{条件:值}},如果不填写条件,删除所有文档 | |
{ | |
justOne: <boolean>, // 可选删除,是否只删除查询到的第一个文档,默认为false,删除所有 | |
writeConcern: <document> // 可选参数,抛出异常的级别。 | |
} | |
) |
操作:
// 删除满足条件的第一条数据 | |
db.user_list.remove({"age":17},{"justOne":true}) | |
// 删除满足条件的所有数据 | |
db.user_list.remove({"name":"laowang"}); |
# 6.4 查询文档
// 直接显示查询的所有,find和findOne的第二个参数,也是一个json对象,一般称之为字段投影,表示设置是否显示或隐藏指定数据字段。 | |
// 获取一条 | |
db.集合.findOne( | |
<query>, // 查询条件 | |
{ | |
<key>: 0, // 隐藏指定字段,例如:"_id":0, | |
<key>: 1, // 显示指定字段,例如:"title":1, | |
.... | |
} | |
) | |
// 获取多条 | |
db.集合.find( | |
<query>, // 查询条件 | |
{ | |
<key>: 0, // 隐藏指定字段,例如:"_id":0, | |
<key>: 1, // 显示指定字段,例如:"title":1, | |
.... | |
} | |
) | |
// 以易读的方式来格式化显示读取到的数据,只能在find方法后面使用。 | |
db.集合.find().pretty() |
比较运算
操作 | 格式 | 语法例子 | SQL 中的类似语句 |
---|---|---|---|
等于 | {<key>:<val>} {<key>:{$eq:<val>}} |
db.集合.find({"name":"xiaoming"}) |
where name = 'xiaoming' |
小于 | {<key>:{$lt:<val>}} |
db.集合.find({"age":{$lt:17}}) |
where age < 17 |
小于或等于 | {<key>:{$lte:<val>}} |
db.集合.find({"age":{$lte:17}}) |
where age <= 17 |
大于 | {<key>:{$gt:<val>}} |
db.集合.find({"age":{$gt:17}}) |
where age > 17 |
大于或等于 | {<key>:{$gte:<val>}} |
db.集合.find({"age":{$gte:17}}) |
where age >= 17 |
不等于 | {<key>:{$ne:<val>}} |
db.集合.find({"age":{$ne:17}}) |
where age != 17 |
包含 | {<key>:{$in:<val>}} |
db.集合.find({"age":{$in:[1,2,3]}}) |
where age in (1,2,3) |
终端运行
db.user_list.find({"age":{$lte:18}}) | |
db.user_list.find({"age":{$gte:18}}) | |
db.user_list.find({"age":{$in:[16,33]}}) | |
db.user_list.find({"child.age":{$in:[3]}}) |
逻辑运算
操作 | 语法 | 语法例子 |
---|---|---|
$and |
{<key>:<val>,<key>:<val>,...} |
db. 集合.find ({key1:value1, key2:value2}) |
$or |
{$or: [{<key>: <val>}, {<key>:<val>}]} |
db. 集合.find ({$or: [{key1: value1}, {key2:value2}]}) |
$and 和 $or |
{<key>:<val>, $or: [{<key>: <val>}, {<key>:<val>}]} {$and:[{$or:[{<key>:<val>},..]},$or:[{<key>:<val>},..]}]} |
db. 集合.find ({key1:value1, $or: [{key1: value1}, {key2:value2}]}) |
$not |
{<key>:{$not:{<$运算符>:<val>}}} |
$not 操作符不支持 $regex 正则表达式操作 |
终端操作:
// 查询age=18 并且 sex=true | |
db.user_list.find({ | |
$and:[ | |
{"age":{$eq:18}}, | |
{"sex":{$eq:true}} | |
] | |
}) | |
// 简写: | |
db.user_list.find({ | |
$and:[ | |
{"age":18}, | |
{"sex":true} | |
] | |
}) | |
// 继续简写; | |
db.user_list.find({ "age":18, "sex":true}) | |
// 查询age=16或者age=18 | |
db.user_list.find({ | |
$or:[ | |
{"age":{$eq:16}}, | |
{"age":{$eq:18}} | |
] | |
}) | |
// 查询年龄!=16的 | |
db.user_list.find({"age":{$not:{$eq:16}}}) | |
db.user_list.find({"age":{$ne:16}}) | |
// 查询age=33的男生 或者 age=18的男生 | |
db.user_list.find({ | |
"sex":true, | |
$or:[ | |
{"age":18}, | |
{"age":33} | |
] | |
}); | |
db.user_list.find({ | |
"sex":true, | |
"age":{ | |
$in:[18,33] | |
} | |
}); | |
db.user_list.find({ | |
$or:[ | |
{$and:[{"sex":true},{"age":18}]}, | |
{$and:[{"sex":true},{"age":33}]}, | |
] | |
}); | |
db.user_list.find({ | |
$or:[ | |
{"sex":true,"age":18}, | |
{"sex":true,"age":33}, | |
] | |
}); |
其他运算符
操作 | 格式 | 语法例子 | 说明 |
---|---|---|---|
$type | {<key>:{$type: <datetype>}} |
db.集合.find({"name":{$type:'string'}}) |
匹配指定键是指定数据类型的文档 number 数值型 string 字符串 bool 布尔类型 object json 文档对象类型 array 数组类型 |
$exists | {<key>:{$exists:<bool>} |
db.集合.find({"title":{$exists:true}}) |
匹配具有指定键的文档,存在指定字段的文档 |
$regex | { <key>:/模式/<修正符>} {<key>:{$regex:/模式/<修正符>}} |
db.集合.find({"name":{$regex:/张$/}}) |
按正则匹配 |
$mod | {<key>: {$mod: [除数, 余数]}} |
db.集合.find({"age":{$mod:[10,0]}}) |
算数运算,取模,语法中举例是 age 除以 10==0 |
终端操作:
db.user_list.insert({"name":"xiaoming","sex":0,"age":"18"}); | |
db.user_list.insert({"name":"xiaoming","sex":1,"age":"18"}); | |
db.user_list.insert({"name":"xiaoming","sex":1,"age":"33"}); | |
db.user_list.insert({"name":"xiaoming","sex":0,"age":"33"}); | |
// $type | |
db.user_list.find({"sex":{$type:"number"}}); | |
db.user_list.find({"age":{$type:"string"}}); | |
// $exists | |
db.user_list.find({"child":{$exists:true}}); | |
// $regex 正则匹配 | |
db.user_list.insert({"name":"xiaoming","sex":0,"age":"18","mobile":"13301234568"}); | |
db.user_list.insert({"name":"xiaoming","sex":1,"age":"18","mobile":"1351234568"}); | |
db.user_list.insert({"name":"xiaoming","sex":1,"age":"33","mobile":"15001234568"}); | |
db.user_list.insert({"name":"xiaoming","sex":0,"age":"33","mobile":"15001234568"}); | |
// 符合手机格式 | |
db.user_list.find({"mobile":{$regex: /1[3-9]\d{9}/ }}); | |
// 不符合手机号码格式的 | |
db.user_list.find({"mobile":{$not:{$regex: /1[3-9]\d{9}/ }}}); | |
// $mod | |
db.user_list.find({"age":{$mod: [3,0] }}); |
自定义条件函数
// 用法1,逻辑比较复杂的情况,可以使用更多的javascript进行运算处理:结果weitrue,则当前数据被查询出来。 | |
db.集合.find({$where: function(){ | |
return <this.字段> <运算符> <条件值>; | |
}}}); | |
// 用法2,相对没那么复杂的: | |
db.集合.find({$where:"<this.字段> <运算符> <条件值>"}); | |
// db.集合.find({$where:"name = 'xiaoming'"}); |
操作:
db.user_list.find({$where: function(){ | |
return this.name=="xiaoming" && this.age<30; | |
}}); | |
// 把字符串作为代码条件执行,当结果为true,则返回当前符合的数据 | |
db.user_list.find({$where:"this.name=='xiaoming' && this.age>30"}); |
排序显示
db.集合.find().sort({<key>:1}) // 升序,默认为升序 | |
db.集合.find().sort({<key>:-1}) // 倒序, |
终端操作:
db.user_list.find().sort({"age":-1}); |
字段投影
find()
方法默认将返回文档的所有数据,但是可以通过设置 find()
的第二个参数 projection,设置值查询部分数据
语法:
// 获取一条 | |
db.集合.findOne( | |
<query>, // 查询条件 | |
{ | |
<key>: 0, // 隐藏指定字段,例如:"_id":0, | |
<key>: 1, // 显示指定字段,例如:"title":1, | |
.... | |
} | |
) | |
// 获取多条 | |
db.集合.find( | |
<query>, // 查询条件 | |
{ | |
<key>: 0, // 隐藏指定字段,例如:"_id":0, | |
<key>: 1, // 显示指定字段,例如:"title":1, | |
.... | |
} | |
) |
操作:
> db.user_list.find({"mobile":{$regex:/^133\d{8}$/}},{"_id":0}).sort({"mobile":-1}) | |
{ "name" : "xiaoming", "mobile" : "13333355678" } | |
{ "name" : "xiaoming", "mobile" : "13333345678" } | |
{ "name" : "xiaoming", "mobile" : "13312345678" } | |
> db.user_list.find({"mobile":{$regex:/^133\d{8}$/}},{"_id":0,"name":0}).sort({"mobile":-1}) | |
{ "mobile" : "13333355678" } | |
{ "mobile" : "13333345678" } | |
{ "mobile" : "13312345678" } | |
> db.user_list.find({"mobile":{$regex:/^133\d{8}$/}},{"name":1}).sort({"mobile":-1}) | |
{ "_id" : ObjectId("60502fb7d5c7a55cc95c1cc4"), "name" : "xiaoming" } | |
{ "_id" : ObjectId("60502fb4d5c7a55cc95c1cc3"), "name" : "xiaoming" } | |
{ "_id" : ObjectId("60502fb1d5c7a55cc95c1cc2"), "name" : "xiaoming" } | |
> db.user_list.find({"mobile":{$regex:/^133\d{8}$/}},{"name":1,"_id":0}).sort({"mobile":-1}) | |
{ "name" : "xiaoming" } | |
{ "name" : "xiaoming" } | |
{ "name" : "xiaoming" } |
限制与偏移
limit
方法用于限制返回结果的数量
skip
方法用于设置返回结果的开始位置
db.集合.find(...).limit(结果数量).skip(跳过数量) |
终端操作:
db.user_list.find({},{"_id":0,"name":1,"age":1}).sort({"age":1}).limit(5); | |
db.user_list.find({},{"_id":0,"name":1,"age":1}).sort({"age":1}).limit(5).skip(5); |
# 6.5 更新文档
// 更新一条 | |
db.集合.update( | |
<query>, // update的查询条件,一般写法:{"属性":{条件:值}} | |
<update>, // update的更新数据,一般写法 { $set:{"属性":"值"} } 或者 { $inc:{"属性":"值"} } | |
{ | |
upsert: <boolean>, // 可选参数,如果文档不存在,是否插入objNew, true为插入,默认是false,不插入 | |
multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新,设置更新1条还是多条 | |
writeConcern: <document> // 可选参数,抛出异常的级别。 | |
} | |
) | |
// 更新多条 | |
db.集合.updateMany( | |
<query>, // update的查询条件,一般写法:{"属性":{条件:值}} | |
<update>, // update的对象,一般写法 { $set:{"属性":"值"} } 或者 { $inc:{"属性":"值"} } | |
{ | |
upsert: <boolean>, // 可选参数,如果文档不存在,是否插入objNew, true为插入,默认是false,不插入 | |
multi: <boolean>, // 可选参数,是否把满足条件的所有数据全部更新 | |
writeConcern: <document> // 可选参数,抛出异常的级别。 | |
} | |
) |
update 更新运算符 [修改器]
操作 | 语法 | 说明 |
---|---|---|
$inc |
db.集合.update({<key1>:<val1>},{$inc:{<key2>:<val2>}}) |
更新 key1=val1 的文档中 key2 的值为 val2,类似 python 的递增递减 递减,则 { $inc:{<key2>:-<val2>} } |
$set |
db.集合.update({<key1>:<val>}, {$set:{<key2>:<val2>}}) |
更新 key1=val1 的文档中 key2 的值为 val2,如果 key2 不存在则新增对应键值对 |
$unset |
db.集合.update({<key1>:<val>}, {$unset:{<key2>:<val2>}}) |
移除 key1=val1 的文档中 key2=val2 这个键值对 |
$push |
db.集合.update({<key1>:<val>}, {$push:{<key2>:<val2>}}) |
给 key1=val1 的文档中 key2 列表增加 1 个数组成员 val2。 key2 必须是数组。 |
$pull |
db.集合.update({<key1>:<val>}, {$pull:{<key2>:<val2>}}) |
与 push 相反,给 key1=val1 的文档中 key2 列表删除 1 个指定成员 val2 |
$pop |
db.集合.update({<key1>:<val>}, {$pop:{<key2>:<val2>}}) |
给 key1=val1 的文档中 key2 列表移除第一个或最后一个成员。 val2 只能是 1 (最后面) 或 - 1 (最前面),与 python 相反 |
终端操作:
// $inc | |
// 把laoli的年龄+10岁 | |
db.user_list.update({"name":"laoli"},{$inc:{"age":10}}); // 更新一条 | |
db.user_list.updateMany({"name":"laoli"},{$inc:{"age":10}}); // 更新多条 | |
// 把laoli的孩子年龄+10岁 | |
db.user_list.update({"name":"laoli"},{$inc:{"child.age":10}}); | |
// $set | |
//更新laoli的手机号码 | |
db.user_list.update({"name":"laoli"},{$set:{"mobile":"18012312312"}}); // 更新一条 | |
// 更新laoli孩子的手机号码 | |
db.user_list.update({"name":"laoli"},{$set:{"child.mobile":"18012312312"}}); | |
// $unset | |
// 移除laoli的性别键值对 | |
db.user_list.update({"name":"laoli"},{$unset:{"sex":true}}); | |
// $push | |
db.user_list.update({"name":"laoli"},{$set:{"lve":["TV","game"]}}); | |
db.user_list.update({"name":"laoli"},{$push:{"lve":"code"}}); // 往列表属性中追加成员 | |
// $addToSet 结合 $each 把一个数组中每一个成员添加到数组中 | |
db.user_list.update({"name":"laoli"},{$addToSet:{"lve":{$each:["code","music","TV"]}}}); | |
// $pull | |
db.user_list.update({"name":"laoli"},{$pull:{"lve":["walk","music"]}}); | |
// $pop | |
db.user_list.update({"name":"laoli"},{$pop:{"lve":-1}}); // 左边移除列表的第一个成员 | |
db.user_list.update({"name":"laoli"},{$pop:{"lve":1}}); // 右边移除列表的最后一个成员 | |
// $rename 字段名重命名 | |
db.user_list.update({"name":"laoli"},{$rename:{"love":"lve"}}); |
# 七、索引操作
我们知道数据库里给数据构建索引通常能够极大的提高数据查询的效率,缩短查询耗时,如果没有索引,
数据库在查询数据时必然会扫描数据表中的每个记录并提取那些符合查询条件的记录。
同理,在 MongoDB 中构建索引也可以提高数据的查询效率和缩短查询耗时,没有索引的情况也是一样,
MongoDB 也会再查询数据时扫描集合中的每个文档并提取符合查询条件的文档。
这种扫描全集合的查询效率是无疑是非常低下的,特别在处理大量的集合数据时,
查询时间可能会达到几十秒甚至几分钟,这对用户体验来说是非常致命的。
文档:https://docs.mongodb.com/manual/indexes/#default-id-index
# 7.1 准备数据
fotmatnumber = function(start, end){ | |
num = Math.round(Math.random() * (end-start)) + start | |
if(num<10){ | |
return "0"+num; | |
}else{ | |
return num; | |
} | |
} | |
rand_title = function(i){ | |
num = Math.round( Math.random() * 10 ); | |
num1 = Math.round( Math.random() * 10 ); | |
return [ | |
"赠送礼品-"+num, | |
"购物狂欢-"+num, | |
"随便买买-"+num, | |
"愉快购物-"+num, | |
"赠送礼物-"+num, | |
"商品购买-"+num, | |
"买多送多-"+num, | |
"买年货-"+num, | |
"买买买买-"+num | |
][num1]; | |
} | |
for(var i=0; i<50000; i++){ | |
db.orders.insert({ | |
"onumber": ( "0000000000000000" + i ).substr( String(i).length ), | |
"date": "20"+fotmatnumber(0,21)+"-"+fotmatnumber(1,12)+"-"+fotmatnumber(1,31), | |
"title": rand_title(i), | |
"user_id": parseInt(i/200)+1, | |
"items" :[{ | |
"goods_id" : parseInt(i/200)+1, | |
"goods_attr" : i, | |
"price" : 100.0 | |
},{ | |
"goods_id" : parseInt(i/200)+2, | |
"goods_attr" : i+1, | |
"price" : 80.0 | |
}] | |
}) | |
if(i%10000==0){ | |
print("已经添加了"+parseInt(i/10000)+"万条数据!"); | |
} | |
} |
# 7.2 注意事项
1.MongoDB 的索引是存储在运行内存 (RAM) 中的,所以必须确保索引的大小不超过内存的限制。
如果索引的大小超过了运行内存的限制,MongoDB 会删除一些索引,这将导致性能下降。
2.MongoDB 的索引在部分查询条件下是不会生效的。
-
正则表达式及非操作符,如 not , 等。
-
算术运算符,如 $mod, 等。
-
$where 自定义查询函数。
-
…
3. 索引会在写入数据(添加、更新和删除)时重排,如果项目如果是写多读少,则建议少使用或者不要使用索引。
4. 一个集合中索引数量不能超过 64 个。
5. 索引名的长度不能超过 128 个字符。
6. 一个复合索引最多可以有 31 个字段。
7.mongodb 索引统一在 system.indexes
集合中管理。这个集合只能通过 createIndex
和 dropIndexes
来操作。
# 7.3 查看索引
// 获取当前集合中已经创建的所有索引信息 | |
db.集合.getIndexes() | |
/* | |
[{ | |
"v" : 2, // 索引版本 | |
"key" : { // 索引的字段及排序方向(1表示升序,-1表示降序) | |
"_id" : 1 // 根据_id字段升序索引 | |
}, | |
"name" : "_id" // 索引的名称 | |
}] | |
*/ | |
// 获取当前集合中已经创建的索引总大小,以字节为单位返回结果 | |
db.集合.totalIndexSize() | |
// 获取当前数据库中所有的索引【不会显示_id主键】 | |
db.system.indexes.find() |
MongoDB 默认会为插入的文档生成 _id
字段(如果应用本身没有指定该字段), _id
是文档唯一的标识,为了保证能根据文档 id 快递查询文档,MongoDB 默认会为集合创建_id 字段的主键索引。
# 7.4 查询分析
与 SQL 语句类似,MongoDB 也提供了一个 explain,供开发者进行查询分析。
explain 的使用有 3 个参数,分别是:queryPlanner、executionStats、allPlansExecution,默认是 queryPlanner,开发中常用的是 executionStats
db.orders.find({"title":"购买商品-19"}).explain("executionStats"); | |
/* | |
{ | |
"queryPlanner" : { # 被查询优化器选择出来的查询计划 | |
"plannerVersion" : 1, # 查询计划版本 | |
"namespace" : "test.orders", # 要查询的集合 | |
"indexFilterSet" : false, # 是否了使用索引 | |
"parsedQuery" : { # 查询条件 | |
"title" : { | |
"$eq" : "购买商品-19" | |
} | |
}, | |
"winningPlan" : { # 最佳执行计划 | |
"stage" : "COLLSCAN", # 扫描类型 / 扫描阶段 | |
"filter" : { # 过滤条件 | |
"title" : { | |
"$eq" : "购买商品-19" | |
} | |
}, | |
"direction" : "forward" # 查询方向,forward 为升序,backward 表示倒序。 | |
}, | |
"rejectedPlans" : [ ] # 拒绝的执行计划 | |
}, | |
"executionStats" : { # 最佳执行计划的一些统计信息 | |
"executionSuccess" : true, # 是否执行成功 | |
"nReturned" : 1, # 返回的结果数 | |
"executionTimeMillis" : 346, # 执行耗时 | |
"totalKeysExamined" : 0, # 索引扫描次数 | |
"totalDocsExamined" : 1000000, # 文档扫描次数,所谓的优化无非是让 totalDocsExamined 和 nReturned 的值接近。 | |
"executionStages" : { # 执行状态 | |
"stage" : "COLLSCAN", # 扫描方式 / 扫描阶段 | |
"filter" : { | |
"title" : { | |
"$eq" : "购买商品-19" | |
} | |
}, | |
"nReturned" : 1, # 返回的结果数 | |
"executionTimeMillisEstimate" : 5, # 预估耗时 | |
"works" : 1000002, # 工作单元数 | |
"advanced" : 1, # 优先返回的结果数 | |
"needTime" : 1000000, | |
"needYield" : 0, | |
"saveState" : 1000, | |
"restoreState" : 1000, | |
"isEOF" : 1, | |
"direction" : "forward", | |
"docsExamined" : 1000000 # 文档检查数目,与 totalDocsExamined 一致 | |
} | |
}, | |
"serverInfo" : { # 服务器信息 | |
"host" : "ubuntu", | |
"port" : 27017, | |
"version" : "4.4.2", | |
"gitVersion" : "15e73dc5738d2278b688f8929aee605fe4279b0e" | |
}, | |
"ok" : 1 | |
} | |
*/ |
stage 的扫描类型:
类型名称 | 描述 | 期望 |
---|---|---|
COLLSCAN | 全表扫描 | False |
IXSCAN | 索引扫描 | True |
FETCH | 根据索引去检索指定 document | True |
IDHACK | 针对_id 进行查询 | True |
COUNTSCAN | count 不使用 Index 进行 count 时返回 | False |
COUNT_SCAN | count 使用了 Index 进行 count 时返回 | True |
SUBPLA | 未使用到索引的 $or 查询时返回 | False |
TEXT | 使用全文索引进行查询时返回 | - |
SORT | 使用 sort 排序但是无 index 时返回 | False |
SKIP | 使用 skip 跳过但是无 index 时返回 | False |
PROJECTION | 使用 limit 限定结果但是无 index 时返回 | False |
# 7.5 创建索引
MongoDB 支持多种类型的索引,包括普通索引、复合索引、多列索引、全文索引、哈希索引、地理位置索引等,每种类型的索引有不同的使用场合。ttl 索引本质上就是普通索引。另外,MongoDB 的全文索引很弱智,如果真要用在开发中,还是建议使用 elasticsearch 或者 Sphinx。
// 创建索引 | |
db.集合.createIndex({ | |
// 单个字段,则为普通索引, // sort的值表示排序,值为1表示升序索引,-1表示降序索引 | |
"字段名1": <sort|type>, // type的值可以是text,表示创建全文索引。db.集合.find({$text:{$search:"字符串"}}) | |
"字段名2": <sort|type>, // 多个字段,则为复合索引 | |
"字段名3": [<值1>,<值2>,...], // 多列索引 | |
.... | |
}, { | |
background: <Boolean>, // 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,默认为false | |
unique: <Boolean>, // 是否建立唯一索引,默认值为false,也叫唯一索引 | |
name: <String>, // 索引的名称,不填写,则MongoDB会通过连接索引的字段名和排序顺序生成一个索引名称 | |
expireAfterSeconds: <integer>, // 设置索引的过期时间,类似redis的expire,也叫TTL索引 | |
sparse: <Boolean>, // 对文档中不存在的字段数据是否不启用索引,默认为False | |
}); | |
// 单字段索引[普通索引] | |
db.集合.createIndex({ | |
"字段名1": <sort>, // sort的值表示排序,值为1表示升序索引,-1表示降序索引 | |
}, { | |
.... | |
}) | |
// 普通索引创建: db.orders.createIndex({"title":1}) | |
// 查询基本使用: db.orders.find({"title":"购买商品-19"}) | |
// 多字段索引,也叫复合索引。[类似mysql里面的联合索引] | |
db.集合.createIndex({ | |
"字段名1": <sort>, // sort的值表示排序,值为1表示升序索引,-1表示降序索引 | |
"字段名2": <sort>, // sort的值表示排序,值为1表示升序索引,-1表示降序索引 | |
}, { | |
.... | |
}) | |
// 复合索引的使用对单条件的查找是没有帮助的,必须多字段[必须包含复合索引的字段]条件使用 | |
// 复合索引创建:db.orders.createIndex({"date":1,"title":1}); | |
// 查询基本使用: | |
// db.orders.find({"date":"2020-09-01","title":"购买商品-1007"}); | |
// db.orders.find({"date":"2020-09-01","onumber":"0000000000001007","title":"购买商品-1007","onumber":}); | |
// 全文索引 | |
db.集合.createIndex({ | |
"字段名1": <type>, // type的值只能是text,表示创建全文索引。db.集合.find({$text:{$search:"字符串"}}) | |
}, { | |
.... | |
}) | |
// 全文索引创建: db.orders.createIndex({"title":"text"}) | |
// 查询基本使用: db.orders.find({$text:{$search:"商品-19"}}).explain("executionStats") | |
// 多列索引[应用的地方是在列表属性] | |
db.集合.createIndex({ | |
"字段名3": [<值1>,<值2>,...], | |
}, { | |
.... | |
}); | |
// 创建测试数据 | |
db.doc.drop() | |
db.doc.insert({"title":"标题1","tags":["python","django"]}) | |
db.doc.insert({"title":"标题1","tags":["python","django"]}) | |
db.doc.insert({"title":"标题1","tags":["python","django"]}) | |
db.doc.insert({"title":"标题2","tags":["java","mvp"]}) | |
db.doc.insert({"title":"标题3","tags":["java","mvp"]}) | |
db.doc.insert({"title":"标题2","tags":["java","mvp"]}) | |
db.doc.insert({"title":"标题3","tags":["python"]}) | |
db.doc.insert({"title":"标题4","tags":["python"]}) | |
db.doc.insert({"title":"标题2","tags":["python","flask"]}) | |
db.doc.insert({"title":"标题3","tags":["java"]}) | |
// 创建多列索引: db.doc.createIndex({"tags":1}) | |
// 查询数据: db.doc.find({"tags":["python"]}).explain("executionStats") | |
// 唯一索引 | |
db.集合.createIndex({ | |
"字段名1": <sort>, | |
}, { | |
unique: true, // 是否建立唯一索引,默认值为false,也叫唯一索引 | |
}) | |
// 创建唯一索引: db.orders.createIndex({"onumber":1},{unique:true}); | |
// 查询数据: db.orders.find({"onumber":"0000000000001019"}).explain("executionStats") | |
// ttl索引 | |
// 使用ttl索引,索引关键字段必须是 Date 类型,如果该字段不是date类型或者文档中不存在该字段,则文档不会进行过期处理 | |
// 数据过期的删除工作是在独立线程内执行的,默认平均60s扫描一次。 | |
// 例如:在文档创建1小时后,删除文档 | |
db.集合.createIndex({"date": 1},{expireAfterSeconds: 3600}) | |
// 在文档创建后,由索引字段值指定的时间删除文档 | |
db.集合.createIndex({"date": 1},{expireAfterSeconds: 0}) // 文档中date字段对应的时间就变成了过期时间了. | |
db.集合.insert( { | |
"date": new Date('2020-02-06 10:00:00'), // 在python中需要通过 utctime | |
"user_id": 2, | |
"username": "xiaoming" | |
}) | |
// 创建索引:db.tasks.createIndex({"expire_time":1},{expireAfterSeconds:0}) | |
// 创建测试数据 | |
db.tasks.insert( { | |
"expire_time": new Date('2021-06-17 22:24:00'), // 在python中需要通过 utctime | |
"user_id": 2, | |
"username": "xiaoming" | |
}); | |
db.tasks.insert( { | |
"expire_time": new Date('2021-06-17 18:25:00'), // 在python中需要通过 utctime | |
"user_id": 2, | |
"username": "xiaoming" | |
}); | |
db.tasks.insert( { | |
"expire_time": new Date('2021-06-17 18:27:00'), // 在python中需要通过 utctime | |
"user_id": 2, | |
"username": "xiaoming" | |
}); | |
// 重建索引[一般是在长期项目运行下来,索引创建时间太久了,性能下降的时候使用。不能在高峰期时运行] | |
db.集合.reIndex(); |
# 7.5 删除索引
// 删除单个索引 | |
db.集合.dropIndex("索引名称") | |
// 删除所有索引 | |
db.集合.dropIndexes() |