mongoDB的用法
中文文档:https://www.mongodb.org.cn/
操作文档:
MongoDB 是一款介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的 NOSQL 数据库。它面向文档存储,而且安装和操作起来都比较简单和容易,而且它支持各种流行编程语言进行操作,如 Python,Node.js,Java,C++,PHP,C# 等。
-
-
数据结构由键值 (key=>value) 对组成。MongoDB 的文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组,单个对象的结构是清晰的。
-
没有复杂的表连接。不需要维护表与表之间的内在关联关系。
-
查询功能强大。MongoDB 的查询功能几乎与 SQL 一样强大,使用基于文档的查询语言,可以对文档进行动态查询。
-
易于调优和扩展。具备高性能、高可用性及可伸缩性等特性
-
应用程序对象与数据库对象天然对应。
-
Mongodb | 描述 | |
---|---|---|
库(database) | 库(database) | |
表(Table) | 集合(Collection) | |
行 / 记录(Row) | 文档(Document) | Document 就是 json 结构的一条数据记录 |
列 / 字段(Col) | 字段 / 键 / 域(Field) | |
主键(Primary Key) | 对象 ID(ObjectId) | _id: ObjectId("10c191e8608f19729507deea") |
索引(Index) | 索引(Index) |
# 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 multiverse3、更新源
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 默认是没有管理员账号的,所以要先切换到 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 进程, 并且在后台运行。
mongo 是一个命令行工具,用于连接一个特定的 mongod 实例。
当我们没有带参数运行 mongo 命令它将使用默认的端口号 27017 和 localhost 进行连接
退出交互终端
exit
# quit()
查看版本
mongo --version
# 或者终端内部使用 version()
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 mapreduceshow dbs show database names show collections show collections </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> current database show users show users </span><span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> current database show profile show most recent system.profile entries with </span><span style="color: rgba(0, 0, 255, 1)">time</span> >=<span style="color: rgba(0, 0, 0, 1)"> 1ms show logs show the accessible logger names show log [name] prints out the </span><span style="color: rgba(0, 0, 255, 1)">last</span> segment of log <span style="color: rgba(0, 0, 255, 1)">in</span> memory, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">global</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)"> is default use </span><db_name><span style="color: rgba(0, 0, 0, 1)"> set current database db.mycoll.</span><span style="color: rgba(0, 0, 255, 1)">find</span>() list objects <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> collection mycoll db.mycoll.</span><span style="color: rgba(0, 0, 255, 1)">find</span>( { a : <span style="color: rgba(128, 0, 128, 1)">1</span> } ) list objects <span style="color: rgba(0, 0, 255, 1)">in</span> mycoll where a == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)"> it result of the </span><span style="color: rgba(0, 0, 255, 1)">last</span><span style="color: rgba(0, 0, 0, 1)"> line evaluated; use to further iterate DBQuery.shellBatchSize </span>=<span style="color: rgba(0, 0, 0, 1)"> x set default number of items to display on shell exit quit the mongo shell</span></pre>
- 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, # 还在活跃的连接数}, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">globalLock</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { # 全局锁相关信息 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalTime</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">105063115000</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">), # mongod启动后到现在的总时间,单位微秒 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">currentQueue</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { # 当前等待锁队列 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">total</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, # 当前全局锁的等待个数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">readers</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, # 当前全局读锁等待个数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">writers</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)"> # 当前全局写锁等待个数 }, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">activeClients</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">total</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, # 当前活跃客户端的个数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">readers</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, # 当前活跃客户端中进行读操作的个数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">writers</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)"> # 当前活跃客户端中进行写操作的个数 } }, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">network</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { # 网络相关 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bytesIn</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">1611</span><span style="color: rgba(0, 0, 0, 1)">), # 数据库接收到的网络传输字节数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bytesOut</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">51269</span><span style="color: rgba(0, 0, 0, 1)">), # 从数据库发送出去的网络传输字节数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">numRequests</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">16</span><span style="color: rgba(0, 0, 0, 1)">), # mongod接收到的总请求次数 }, # 操作计数器 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">opcounters</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), # 本次mongod实例启动至今收到的插入操作总数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">query</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">287</span><span style="color: rgba(0, 0, 0, 1)">), # 本次mongod实例启动至今收到的查询总数。 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">update</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), # 本次mongod实例启动至今收到的更新操作总数 。 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), # 本次mongod实例启动至今的删除操作总数。 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">getmore</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), # 本次mongod实例启动至今“getmore”操作的总数。 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">command</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">588</span><span style="color: rgba(0, 0, 0, 1)">)# 本次mongod实例启动至今向数据库发出的命令总数 。 }, # 存储引擎,是MongoDB的核心组件,负责管理数据如何存储在硬盘(Disk)和内存(Memory)上 # MongoDB 支持多种不同的存储引擎(Storage Engine),MongoDB支持的存储引擎有:WiredTiger,MMAPv1和In</span>-<span style="color: rgba(0, 0, 0, 1)">Memory。 # </span><span style="color: rgba(128, 0, 128, 1)">1</span>. WiredTiger,将数据持久化存储在硬盘文件中;从MongoDB <span style="color: rgba(128, 0, 128, 1)">3.2</span><span style="color: rgba(0, 0, 0, 1)"> 版本开始,成为MongDB默认存储引擎 # </span><span style="color: rgba(128, 0, 128, 1)">2</span>. In-<span style="color: rgba(0, 0, 0, 1)">Memory,将数据存储在内存中 # </span><span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">. MMAPv1,将数据持久化存储在硬盘文件中; # WiredTiger是比MMAPv1更好用,更强大的存储引擎,WiredTiger的写操作会先写入缓存(Cache)中,并持久化到WAL(Write ahead log,写日志),每60s或日志文件达到2GB时会做一次Checkpoint(检查点),将当前数据进行持久化,产生一个新的快照。Wiredtiger连接初始化时,首先将数据恢复至最新的快照状态,然后根据WAL恢复数据,以保证存储可靠性。 # Checkpoint,检测点。将内存中的数据变更冲刷到磁盘中的数据文件中,并做一个标记点。 # 表示此前的数据表示已经持久存储在了数据文件中,此后的数据变更存在于内存和日志中. # 是一种让数据库redo(重做)和data(数据)文件保持一致的机制。 # 并非Mongodb独有的,mysql中的InnoDB也有。 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">storageEngine</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">wiredTiger</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">supportsCommittedReads</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oldestRequiredTimestampForCrashRecovery</span><span style="color: rgba(128, 0, 0, 1)">"</span> : Timestamp(<span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">supportsPendingDrops</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">dropPendingIdents</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">supportsTwoPhaseIndexBuild</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">supportsSnapshotReadConcern</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">readOnly</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">persistent</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">backupCursorOpen</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)"> }, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">transactions</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { # 事务,mongodb4.0以后新增特性 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">retriedCommandsCount</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">retriedStatementsCount</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">transactionsCollectionWriteCount</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">currentActive</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">currentInactive</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">currentOpen</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalAborted</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalCommitted</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalStarted</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalPrepared</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalPreparedThenCommitted</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">totalPreparedThenAborted</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">currentPrepared</span><span style="color: rgba(128, 0, 0, 1)">"</span> : NumberLong(<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) }, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">locks</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:{ # 锁相关 }, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mem</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : { # 内存相关 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bits</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">64</span><span style="color: rgba(0, 0, 0, 1)">, # 操作系统位数 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">resident</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">, # 物理内存消耗,单位:M </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">virtual</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(128, 0, 128, 1)">1566</span><span style="color: rgba(0, 0, 0, 1)">, # 虚拟内存消耗 </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">supported</span><span style="color: rgba(128, 0, 0, 1)">"</span> : <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)"> # 是否显示额外的内存信息 },
}
- db.getMongo()
- show logs
show logs
# global
# startupWarnings
如果要查看具体文件的日志。
show log global
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,设置首行为导入字段 |
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>" ... ] }
管理员可以管理自己的数据库,但是不能直接管理其他数据库,要先在 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 数据库账号,不能进行其他数据库的操作
# 进入 / 切换数据库到 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"} ] })
use mofang
show users
需要切换到 admin 中使用账号管理员的权限进行操作
use admin db.auth("root","123456")db.system.users.find() # 只能在 admin 数据库中使用。
db.system.users.remove(json 条件)
要切换到 admin 用户中
# 有多种删除方式,下面是根据 user 用户名删除用户 db.system.users.remove({user:"mofang"});# 删除效果:
WriteResult({ "nRemoved" : 1 }) # nRemoved 大于 0 表示成功删除管理员,等于 0 则表示没有删除。
必须切换到对应的数据库下
db.changeUserPassword("账户名", "新密码")
use mofang # 注册必须保证有这个管理员 db.changeUserPassword("mofang", "123456")
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()
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
}
在 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})
show collections # 或 show tables 或 db.getCollectionNames()
db. 集合.drop()
db.getCollection("集合") db. 集合
MongoDB Enterprise > db.user_list
mofang.user_list
db.printCollectionStats()
描述 | |
---|---|
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 | 正则表达式 |
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")
// ]
// }
db. 集合.remove( <query>, // removed 的条件,一般写法:{"属性":{ 条件: 值}},如果不填写条件,删除所有文档 { justOne: <boolean>, // 可选删除,是否只删除查询到的第一个文档,默认为 false,删除所有 writeConcern: <document> // 可选参数,抛出异常的级别。 } )
操作:
// 删除满足条件的第一条数据 db.user_list.remove({"age":17},{"justOne":true}) // 删除满足条件的所有数据 db.user_list.remove({"name":"laowang"});
// 直接显示查询的所有,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});
// 获取一条 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);
// 更新一条 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> // 可选参数,抛出异常的级别。
}
)
语法 | ||
---|---|---|
$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"}});
前面学习过 MySQL,我们知道数据库里给数据构建索引通常能够极大的提高数据查询的效率,缩短查询耗时,如果没有索引,数据库在查询数据时必然会扫描数据表中的每个记录并提取那些符合查询条件的记录。同理,在 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)+"万条数据!");
}
}
-
如果索引的大小超过了运行内存的限制,MongoDB 会删除一些索引,这将导致性能下降。
-
MongoDB 的索引在部分查询条件下是不会生效的。
-
正则表达式及非操作符,如
$nin
,$not
, 等。 -
算术运算符,如 $mod, 等。
-
$where 自定义查询函数。
-
...
-
-
索引会在写入数据(添加、更新和删除)时重排,如果项目如果是写多读少,则建议少使用或者不要使用索引。
-
一个集合中索引数量不能超过 64 个。
-
索引名的长度不能超过 128 个字符。
-
一个复合索引最多可以有 31 个字段。
-
mongodb 索引统一在
system.indexes
集合中管理。这个集合只能通过createIndex
和dropIndexes
// 获取当前集合中已经创建的所有索引信息 db. 集合.getIndexes() /* [{ "v" : 2, // 索引版本 "key" : {// 索引的字段及排序方向 (1 表示升序,-1 表示降序) "_id" : 1 // 根据 _id 字段升序索引 }, "name" : "_id" // 索引的名称 }] */ // 获取当前集合中已经创建的索引总大小,以字节为单位返回结果 db. 集合.totalIndexSize() // 获取当前数据库中所有的索引【不会显示 _id 主键】 db.system.indexes.find()
与 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 |
// 创建索引 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();
// 删除单个索引 db. 集合.dropIndex("索引名称")// 删除所有索引
db. 集合.dropIndexes()