MongoDB
简介
MongoDB 有哪些特点
● 文档型数据库 ● 高性能 ● 灵活性 ● 可扩展性 ● 强大的查询语言 ● 优异的性能 ● 高性能:支持使用嵌入数据时,减少系统I/O负担,支持子文档查询 ● 多种查询类型支持,且支持数据聚合查询、文本检索、地址位置查询 ● 高可用、水平扩展:支持副本集与分片 ● 多种存储引擎:WiredTiger , In-Memory MongoDB 适用于哪些场景
1、需要处理大量的低价值数据,且对数据处理性能有较高要求
比如,对微博数据的处理就不需要太高的事务性,但是对数据的存取性能有很高的要求,这时就非常适合使用 MongoDB。
2、需要借助缓存层来处理数据
因为 MongoDB 能高效的处理数据,所以非常适合作为缓存层来使用。将 MongoDB 作为持久化缓存层,可以避免底层存储的资源过载。
3、需要高度的伸缩性
对关系型数据库而言,当表的大小达到一定数量级后,其性能会急剧下降。这时可以使用多台 MongoDB 服务器搭建一个集群环境,实现最大程度的扩展,且不影响性能。
安装 MongoDB
1.在 macOS 中安装 MongoDB
使用 homebrew 安装 MongoDB
- 安装 Command Line Tools for Xcode
如果你电脑上安装了 XCode 软件开发工具(在App Store中安装Xcode),Command Line Tools for Xcode已经给你安装好了。
也可以直接安装 Command Line Tools for Xcode。在终端输入以下代码完成安装:
xcode-select --install
- 安装 Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
- 添加 MongoDB 安装源到 Homebrew
brew tap mongodb/brew
- 使用 homebrew 安装 MongoDB
brew install mongodb-community@4.4
该安装除安装必要的二进制文件之外,还会创建运行 MongoDB 服务所需的文件目录:
- MongoDB 配置文件:/usr/local/etc/mongod.conf
- 日志文件存储目录:/usr/local/var/log/mongodb
- 数据文件存储目录:/usr/local/var/mongodb
管理 MongoDB 服务
启动 MongoDB
启动 MongoDB 并运行在后台。
shell brew services start mongodb-community@4.4
或者手动启动 MongoDB,运行在前台。也可以加入 --fork 参数运行在后台。
shell mongod --config /usr/local/etc/mongod.conf
查看 MongoDB 服务运行状态
要验证MongoDB是否正在运行,请在正在运行的进程中搜索 mongod:
shell ps aux | grep -v grep | grep mongod
还可以通过查看日志文件以查看 mongod 进程的当前状态:/usr/local/var/log/mongodb/mongo.log
。
停止 MongoDB
brew services stop mongodb-community@4.4
卸载 MongoDB
brew uninstall mongodb-community@4.4
2.在 Windows 中安装 MongoDB
这里以 Windows 手动安装 MongoDB 为例。
1、下载 MongoDB 安装包
www.mongodb.com/try/downloa…
2、解压压缩包,将解压出来的资源文件放到一个稳定的目录中
3、关于 MongoDB 软件包目录文件
文件名 | 说明 |
---|---|
mongod.exe | 服务端,用来启动数据库服务的 |
mongo.exe | 客户端,用来连接数据库服务操作数据库 |
4、将 MongoDB 安装包中的 bin 目录配置到环境 PATH 变量配置 PATH 环境变量的目的是为了能够在命令行中的任何位置都能够访问到 bin 目录中的可执行程序。
C:\Users\HMSJ1\mongodb-win32-x86_64-windows-4.4.18\bin
5、确认是否配置成功()
mongod --version
注意:如果是配置环境变量之前打开的命令行,则需要在配置完环境变量之后将命令行重启才能生效。
启动和停止 MongoDB 数据库服务
mongod --dbpath="数据存储目录"
mongod 默认监听 127.0.0.1:27017。
如果单独执行 mongod,它会默认使用执行 mongod 命令所处磁盘根目录/data/db 作为数据存储目录。
正确的操作流程:
- 在本地目录中新增一个data目录
- 复制data目录的完整路径
"C:\Users\HMSJ1\mongodb-win32-x86_64-windows-4.4.18\data"
- 启动命令行输入
mongod --dbpath="C:\Users\HMSJ1\mongodb-win32-x86_64-windows-4.4.18\data"
启动 mongo Shell 并连接到 MongoDB
连接默认端口上的本地 MongoDB 服务
不能关闭已经启动的mongod
您可以在没有任何命令行选项的情况下运行 mongo shell,以使用默认端口 27017 连接到在本地主机上运行的 MongoDB 实例
mongo
连接非默认端口上的本地 MongoDB 服务
要明确指定端口,请包括 --port 命令行选项。例如,要使用非默认端口 28015 连接到在 localhost 上运行的 MongoDB 实例,请执行以下操作:
mongo --port 28015
连接远程主机上的 MongoDB 服务
连接远程主机上的 MongoDB 服务需要明确指定主机名和端口号。 您可以指定一个连接字符串。例如,要连接到在远程主机上运行的 MongoDB 实例,请执行以下操作
mongo "mongodb://mongodb0.example.com:28015"
您可以使用命令行选项 --host <主机>:<端口>。例如,要连接到在远程主机上运行的 MongoDB 实例,请执行以下操作:
mongo --host mongodb0.example.com --port 28015
连接具有身份认证的 MongoDB 服务
您可以在连接字符串中指定用户名,身份验证数据库以及可选的密码。例如,以alice用户身份连接并认证到远程MongoDB实例:
mongo "mongodb://alice@mongodb0.examples.com:28015/?authSource=admin"
注意:如果您指定--password而不输入用户密码,则外壳程序将提示您输入密码
MongoDB基本操作
存储结构:数据库——>集合——>文档
MongoDB 将数据记录存储为 BSON 文档,BSON(Binary JSON)是 JSON 文档的二进制表示形式,它比 JSON 包含更多的数据类型
数据库
数据库名称规则
- 不区分大小写,但是建议全部小写
- 不能包含空字符。
- 数据库名称不能为空,并且必须少于64个字符。
- Windows 上的命名限制
- 不能包括 /. "$*<>:|? 中的任何内容
- Unix 和 Linux 上的命名限制
- 不能包括 /. "$ 中的任何字符
数据库操作
show dbs //查看数据库列表
db //查看当前数据库
use <数据库名称> // use test 创建或切换数据库
db.dropDatabase() //删除当前数据库
集合
集合名称规则
集合名称应以下划线或字母字符开头,并且:
- 不能包含 $
- 不能为空字符串
- 不能包含空字符
- 不能以 . 开头
- 长度限制
- 版本 4.2 最大 120 个字节
- 版本 4.4 最大 255 个字节
集合操作
db.test.insert({name:1}) //创建test集合并在集合中写入数据
db.createCollection()//方法来显式创建具有各种选项的集合,例如设置最大大小或文档验证规则
show collections //查看集合
db.集合名称.drop() //删除集合 db.test.drop()
文档
文档名称规则
文档对字段名称有以下限制:
- 字段名称 _id 保留用作主键;它的值在集合中必须是唯一的,不可变的,并且可以是数组以外的任何类型。
- 字段名称不能包含空字符。
- 顶级字段名称不能以美元符号 $ 开头。
- 从 MongoDB 3.6 开始,服务器允许存储包含点 . 和美元符号 $ 的字段名称
常用的数据类型
类型 | 整数标识符 | 别名(字符串标识符) | 描述 |
---|---|---|---|
Double | 1 | “double” | 双精度浮点值。用于存储浮点值。 |
String | 2 | “string” | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Object | 3 | “object” | 用于内嵌文档 |
Array | 4 | “array” | 用于将数组或列表或多个值存储为一个键。 |
Binary data | 5 | “binData” | 二进制数据。用于存储二进制数据。 |
ObjectId | 7 | “objectId” | 对象 ID。用于创建文档的 ID。 |
Boolean | 8 | “bool” | 布尔值。用于存储布尔值(真/假)。 |
Date | 9 | “date” | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Null | 10 | “null” | 用于创建空值。 |
Regular Expression | 11 | “regex” | 正则表达式类型。用于存储正则表达式。 |
32-bit integer | 16 | “int” | 整型数值。用于存储 32 位整型数值。 |
Timestamp | 17 | “timestamp” | 时间戳。记录文档修改或添加的具体时间。 |
64-bit integer | 18 | “long” | 整型数值。用于存储 64 位整型数值。 |
Decimal128 | 19 | “decimal” | 数值类型。常用于存储更精确的数字,例如货币。 |
文档操作(CRUD)
1. 创建文档(create)
方法 | 描述 |
---|---|
db.collection.insertOne() | 插入单个文档到集合中 |
db.collection.insertMany() | 插入多个文档到集合中 |
db.collection.insert() | 将1个或多个文档插入到集合中 |
// 插入单个文档
db.inventory.insertOne(
{ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
// 插入多个文档
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
{ item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
{ item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
// 插入1个或多个文档
db.inventory.insert( { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } })
db.inventory.insert([
{ item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
{ item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
{ item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])
2. 查询文档(read)
方法 | 描述 |
---|---|
db.collection.find(query, projection) | query :可选,使用查询操作符指定查询条件;projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略) |
db.collection.findOne() | 单个查询 |
基础查询
- 查询所有文档
// 查询所有文档 db.inventory.find( {} ) //等价于 SQL 中的 SELECT * FROM inventory 语句 db.inventory.find().pretty() //格式化打印结果
- 相同条件查询
db.inventory.find( { status: "D" } ) //等价于 SQL 中的 SELECT * FROM inventory WHERE status = "D" 语句
- 多个查询条件同时满足(AND条件)
//检索状态为“ A”且数量小于($ lt)30的清单集合中的所有文档 db.inventory.find( { status: "A", qty: { $lt: 30 } } ) //等价于 SQL 中的 SELECT * FROM inventory WHERE status = "A" AND qty < 30
- 满足其中一个查询条件(OR条件)
//检索状态为 A 或数量小于 $lt30 的集合中的所有文档 db.inventory.find({ $or: [ { status: "A" }, { qty: { $lt: 30 } } ] })//等价于 SQL 中的SELECT * FROM inventory WHERE status = "A" OR qty < 30
- 指定 AND 和 OR 条件
//检索状态为“ A”且qty小于($ lt)30或item以字符p开头的所有文档 db.inventory.find({ status: "A", $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ] }) //等价于 SQL 中的SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")
- 查询运算符指定条件
//检索状态为“ A”或“ D”所有文档 db.inventory.find( { status: { $in: [ "A", "D" ] } } )//等价于 SQL 中的SELECT * FROM inventory WHERE status in ("A", "D")
- 查询运算符
查询嵌套文档
- 匹配嵌套文档(完全匹配包括字段顺序)
//查询选择字段大小等于文档 {h: 14, w: 21, uom: "cm"} 的所有文档 db.inventory.find({ size: { h: 14, w: 21, uom: "cm" } }) //整个嵌入式文档上的相等匹配要求与指定的 <value> 文档完全匹配,包括字段顺序
- 查询嵌套字段(使用点符号查询时,字段和嵌套字段必须在引号内)
- 在嵌套字段上指定相等匹配
//查询嵌套在 size 字段中的 uom 字段等于 "in" 的所有文档 db.inventory.find({ "size.uom": "in" })
- 使用查询运算符指定匹配项
//查询在 size 字段中嵌入的字段 h 上使用小于运算符 $lt db.inventory.find({ "size.h": { $lt: 15 } }) //查询选择嵌套字段 h 小于 15,嵌套字段 uom 等于 "in",状态字段等于 "D" 的所有文档 db.inventory.find({ "size.h": { $lt: 15 }, "size.uom": "in", status: "D" })
- 在嵌套字段上指定相等匹配
- 查询数组
- 匹配一个数组(匹配的精确数组,包括元素的顺序)
$all 可以不考虑顺序或该数组中的其他元素
//按指定顺序恰好具有两个元素 "red" 和 "blank" 的数组 db.inventory.find({ tags: ["red", "blank"] }) //找到一个同时包含元素 "red" 和 "blank" 的数组,而不考虑顺序或该数组中的其他元素,请使用 $all 运算符 db.inventory.find({ tags: { $all: ["red", "blank"] } })
- 查询数组中的元素
//查询tags数组字段是否包含至一个具有指定值的元素 db.inventory.find({ tags: "red" }) //查询数组 dim_cm 包含至少一个值大于 25 的元素的所有文档 db.inventory.find({ dim_cm: { $gt: 25 } })
- 为数组元素指定多个条件
在数组元素上指定复合条件时,可以指定查询,以使单个数组元素满足这些条件,或者数组元素的任何组合均满足条件。
- 使用数组元素上的复合过滤条件查询数组
//一个元素可以满足大于 15 的条件,而另一个元素可以满足小于 20 的条件;或者单个元素可以满足以下两个条件 db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } )
- 查询满足多个条件的数组元素
使用 $elemMatch 运算符可以在数组的元素上指定多个条件,以使至少一个数组元素满足所有指定的条件
//查询在 dim_cm 数组中包含至少一个同时 大于22 和 小于30 的元素的文档 db.inventory.find({ dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } })
- 通过数组索引位置查询元素
使用点符号,可以为数组的特定索引或位置指定元素的查询条件。该数组使用基于零的索引(注意:使用点符号查询时,字段和嵌套字段必须在引号内)
//查询数组 dim_cm 中第二个元素大于 25 的所有文档 db.inventory.find( { "dim_cm.1": { $gt: 25 } } )
- 通过数组长度查询数组
使用 $size 运算符可按元素数量查询数组
//查询数组标签具有3个元素的文档 db.inventory.find( { "tags": { $size: 3 } } )
- 使用数组元素上的复合过滤条件查询数组
- 匹配一个数组(匹配的精确数组,包括元素的顺序)
$all 可以不考虑顺序或该数组中的其他元素
- 查询嵌入文档的数组
db.inventory.insertMany( [ { item: "journal", instock: [ { warehouse: "A", qty: 5 }, { warehouse: "C", qty: 15 } ] }, { item: "notebook", instock: [ { warehouse: "C", qty: 5 } ] }, { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 15 } ] }, { item: "planner", instock: [ { warehouse: "A", qty: 40 }, { warehouse: "B", qty: 5 } ] }, { item: "postcard", instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] } ]);
- 查询嵌套在数组中的文档
整个嵌入式/嵌套文档上的相等匹配要求与指定文档(包括字段顺序)完全匹配
// db.inventory.find({ "instock": { warehouse: "A", qty: 5 } })
- 在文档数组中的字段上指定查询条件
- 在嵌入文档数组中的字段上指定查询条件
如果您不知道嵌套在数组中的文档的索引位置,请使用点(。)和嵌套文档中的字段名称来连接数组字段的名称
//数组中包含至少一个嵌入式文档的嵌入式文档,这些嵌入式文档包含值小于或等于20的字段qty db.inventory.find( { 'instock.qty': { $lte: 20 } } )
- 使用数组索引在嵌入式文档中查询字段
使用点表示法,您可以为文档中特定索引或数组位置处的字段指定查询条件。该数组使用基于零的索引(注意:使用点符号查询时,字段和索引必须在引号内。)
//数组的第一个元素是包含值小于或等于20的字段qty的文档 db.inventory.find( { 'instock.0.qty': { $lte: 20 } } )
- 在嵌入文档数组中的字段上指定查询条件
如果您不知道嵌套在数组中的文档的索引位置,请使用点(。)和嵌套文档中的字段名称来连接数组字段的名称
- 为文档数组指定多个条件
在嵌套在文档数组中的多个字段上指定条件时,可以指定查询,以使单个文档满足这些条件,或者数组中文档的任何组合(包括单个文档)都满足条件
- 单个嵌套文档在嵌套字段上满足多个查询条件
使用$ elemMatch运算符可在一组嵌入式文档上指定多个条件,以使至少一个嵌入式文档满足所有指定条件
//查询数组中至少有一个嵌入式文档的文档,这些文档同时包含等于5的字段qty和等于A的字段仓库 db.inventory.find( { "instock": { $elemMatch: { qty: 5, warehouse: "A" } } } ) //查询数组中至少有一个嵌入式文档的嵌入式文档包含的字段qty大于10且小于或等于20 db.inventory.find( { "instock": { $elemMatch: { qty: { $gt: 10, $lte: 20 } } } } )
- 元素组合满足标准
如果数组字段上的复合查询条件未使用$ elemMatch运算符,则查询将选择其数组包含满足条件的元素的任意组合的那些文档。
//查询匹配文档,其中嵌套在库存数组中的任何文档的qty字段都大于10,而数组中的任何文档(但不一定是同一嵌入式文档)的qty字段小于或等于20 db.inventory.find( { "instock.qty": { $gt: 10, $lte: 20 } } ) //查询数组中具有至少一个包含数量等于5的嵌入式文档和至少一个包含等于A的字段仓库的嵌入式文档(但不一定是同一嵌入式文档)的文档 db.inventory.find( { "instock.qty": 5, "instock.warehouse": "A" } )
- 单个嵌套文档在嵌套字段上满足多个查询条件
使用$ elemMatch运算符可在一组嵌入式文档上指定多个条件,以使至少一个嵌入式文档满足所有指定条件
- 查询嵌套在数组中的文档
整个嵌入式/嵌套文档上的相等匹配要求与指定文档(包括字段顺序)完全匹配
指定从查询返回的项目字段
- 返回匹配文档中所有字段
//返回状态为 "A" 的清单集合中所有文档的所有字段 db.inventory.find( { status: "A" } )
- 仅返回指定字段和 _id 字段
find方法中的第二个参数可以指定返回项目数据
//匹配的文档中仅返回项目,状态和默认情况下的 _id 字段 db.inventory.find( { status: "A" }, { item: 1, status: 1 } )
- 禁止 _id 字段
//通过将投影中的 _id 字段设置为 0 来从结果中删除 _id 字段 db.inventory.find( { status: "A" }, { item: 1, status: 1, _id: 0 } )
- 返回所有但排除的字段
// db.inventory.find( { status: "A" }, { status: 0, instock: 0 } )
- 返回嵌入式文档中的特定字段
使用点表示法引用嵌入式字段,并在投影文档中将其设置为1
db.inventory.find( { status: "A" }, { item: 1, status: 1, "size.uom": 1 } ) // 从MongoDB 4.4 开始,您还可以使用嵌套形式指定嵌入式字段,例如 {item: 1, status: 1, size: {uom: 1}}
- 禁止嵌入文档中的特定字段
使用点表示法引用投影文档中的嵌入字段并将其设置为0
db.inventory.find( { status: "A" }, { "size.uom": 0 } ) //从 MongoDB 4.4 开始,您还可以使用嵌套形式指定嵌入式字段,例如 { size: { uom: 0 } }
- 在数组中的嵌入式文档上投射
使用点表示法可将特定字段投影在嵌入数组的文档中
db.inventory.find( { status: "A" }, { item: 1, status: 1, "instock.qty": 1 } )
- 返回数组中的项目特定数组元素
含数组的字段,MongoDB 提供以下用于操纵数组的投影运算符:
$elemMatch,$slice 和$
// $slice 投影运算符返回库存数组中的最后一个元素 db.inventory.find( { status: "A" }, { item: 1, status: 1, instock: { $slice: -1 } } )
$elemMatch,$slice 和 $ 是投影要包含在返回数组中的特定元素的唯一方法。例如,您不能使用数组索引来投影特定的数组元素。例如{“ instock.0”:1}投影不会投影第一个元素的数组
指定从查询返回的项目字段
MongoDB 中的不同查询运算符对空值的处理方式不同
js db.inventory.insertMany([ { _id: 1, item: null }, { _id: 2 } ])
- 相等过滤器
//{item: null} 查询将匹配包含其值为 null 的 item 字段或不包含 item 字段的文档 db.inventory.find( { item: null } ) //该查询返回集合中的两个文档
- 类型检查
{ item: { $type: 10 } } 查询仅匹配包含 item 字段,其值为 null 的文档;即 item 字段的值为 BSON 类型为 Null(类型编号10):
//仅返回 item 字段值为 null 的文档 db.inventory.find( { item : { $type: 10 } } )
- 存在检查
//仅返回不包含 item 字段的文档 db.inventory.find( { item : { $exists: false } } )
3. 更新文档(update)
方法 | 描述 |
---|---|
db.collection.updateOne(<filter>, <update>, <options>) | 更新单个 |
db.collection.updateMany(<filter>, <update>, <options>) | 更新多个 |
db.collection.replaceOne(<filter>, <update>, <options>) | 替换单个 |
参数解释:
- filter:筛选条件,使用相同于find()方法中query参数
- update:更新的数据
- options:选项
// 更新单个文档
db.inventory.updateOne(
{ item: "paper" },
{
$set: { "size.uom": "cm", status: "P" },
$currentDate: { lastModified: true }
}
)
// 更新多个文档
db.inventory.updateMany(
{ "qty": { $lt: 50 } },
{
$set: { "size.uom": "in", status: "P" },
$currentDate: { lastModified: true }
}
)
// 更新操作:
// 使用 $set 运算符将 size.uom 字段的值更新为 "in",将状态字段的值更新为 "p"
// 使用 $currentDate 运算符将 lastModified 字段的值更新为当前日期。如果 lastModified 字段不存在,则 $currentDate 将创建该字段
// 替换文档
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
) //要替换 _id 字段以外的文档的全部内容
4. 删除文档(delete)
方法 | 描述 |
---|---|
db.collection.deleteMany(<filter>,<options>) | 删除多个 |
db.collection.deleteOne(<filter>,<options>) | 删除单个 |
参数解释: |
- filter:筛选条件,使用相同于find()方法中query参数
- options:选项
// 删除所有文档
db.inventory.deleteMany({})
// 删除所有符合条件的文档
db.inventory.deleteMany({ status : "A" }) //删除inventory集合中状态字段等于“ A”的所有文档
// 删除1个符合条件的文档
db.inventory.deleteOne( { status: "D" } ) //删除状态为“ D”的第一个文档