MongoDB是一个基于分布式文件存储的数据库。由 C++语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 json 的 bson 格式,因此可以存储比较复杂的数据类型。Mongo 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
Docker 安装
文档使用 |
mongoDBShell CRUD 操作
连接 mongo
进入容器 |
这里需要注意你创建用户使用的数据库是哪一个。如果在非注册数据库认证,可能会认证失败。使用代码连接时,也需要提供注册时用的数据库。
为了避免麻烦,还是把所有用户都注册在 admin 里,方便管理。
插入文档
- 如果该集合当前不存在,则插入操作将创建该集合。
- 在 MongoDB 中,存储在集合中的每个文档都需要一个唯一的 _id 字段作为主键。如果插入的文档省略了 _id 字段,MongoDB 驱动程序会自动为 ObjectId 字段生成一个 _id。
- MongoDB 中的所有写入操作在单个文档级别上都是原子操作。
- 对于写关注,您可以指定 MongoDB 请求的写操作确认级别。
插入一条数据
插入一条数据 |
插入多条数据
db.inventory.insertMany([ |
其他插入方法
db.collection.updateOne()与upsert: true选项一起使用时。db.collection.updateMany()与upsert: true选项一起使用时。db.collection.findAndModify()与upsert: true选项一起使用时。db.collection.findOneAndUpdate()与upsert: true选项一起使用时。db.collection.findOneAndReplace()与upsert: true选项一起使用时。db.collection.bulkWrite()
查询文档
对嵌入/嵌套文档的查询
准备数据
db.inventory.insertMany( [ |
使用点符号对嵌套字段进行查询
db.inventory.find( { "size.uom": "in" } ) |
使用查询运算符指定匹配
{ <field1>: { <operator1>: <value1> }, ... } |
匹配嵌入式/嵌套文档
不建议使用这种方式进行查询,因为需要完全匹配(包括字段顺序)
{ <field>: <value> } |
查询数组
准备数据
db.inventory.insertMany([ |
匹配数组
{ <field>: <value> } <value> 是要匹配的精确数组,包括元素的顺序。 |
查询数组元素
要查询数组字段是否至少包含一个具有指定值的元素,请使用筛选器 { <field>: <value> },其中的 <value> 是元素值 |
查询嵌入式文档数组
准备数据
db.inventory.insertMany( [ |
查询
以下示例选择 instock 数组中的元素与指定文档匹配的所有文档: |
查询返回的项目字段
准备数据
db.inventory.insertMany( [ |
查询
仅返回指定字段和 _id 字段 |
查询 Null 字段或缺失字段
准备数据
db.inventory.insertMany([ |
查询
{ item : null } 查询将匹配包含值为 null 的 item 字段或者不包含 item 字段的文档。 |
执行长期运行的快照查询
快照查询允许您读取最近单个时间点出现的数据。
从 MongoDB 5 开始。 0 ,可以使用读关注(read concern)”snapshot”查询从节点上的数据。此功能提高了应用程序读取的多功能性和韧性。您无需创建数据的静态副本,将其移至单独的系统中,也无需手动隔离这些长时间运行的查询,以免干扰操作工作负载。相反,您可以对实时事务性数据库执行长时间运行的查询,同时读取一致状态的数据。
在从节点上使用读关注(read concern)”snapshot”不会影响应用程序的写入工作负载。只有应用程序读取受益于隔离到从节点的长时间运行查询。
当您需要执行以下操作时,请使用快照查询:
执行多个相关查询,并确保每个查询从同一时间点读取数据。
确保您从过去某个时间点读取的数据处于一致状态。
比较本地读关注和快照读关注
当 MongoDB 使用默认的”local”读关注(read concern)执行长时间运行的查询时,查询结果可能包含与查询同时发生的写入操作的数据。因此,查询可能会返回意外或不一致的结果。
为避免这种情况,请创建一个会话并指定读关注(read concern)”snapshot” 。使用读关注(read concern)”snapshot”时,MongoDB 以快照隔离方式运行查询,这意味着您的查询将读取最近单个时间点出现的数据。
ctx := context.TODO() |
更新文档
准备数据
db.inventory.insertMany( [ |
更新操作
要更新文档,MongoDB 提供了更新操作符(例如$set )来修改字段值。 |
删除文档
- db.collection.deleteMany()
- db.collection.deleteOne()
即使从集合中删除所有文档,删除操作也不会删除索引。
准备数据
db.inventory.insertMany( [ |
删除
删除所有 |
批量写入操作
db.collection.bulkWrite() 方法支持执行批量插入、更新和删除操作。
批量写操作可以是有序的,也可以是无序的。
对于有序的操作列表,MongoDB 以串行方式执行操作。如果在处理其中的一个写入操作期间出现错误,MongoDB 将返回而不处理列表中的任何其余写入操作
对于无序列表的操作,MongoDB 可以并行执行操作,但不能保证这种行为。如果在处理其中一个写入操作期间出现错误,MongoDB 将继续处理列表中剩余的写入操作。
在分片集合上执行操作的有序列表通常比执行无序列表慢,因为对于有序列表,每个操作都必须等待前一个操作完成。
默认情况下,bulkWrite() 执行 ordered 操作。要指定 unordered 写入操作,请在选项文档中设置 ordered : false。
可重试写入
可重试写入允许 MongoDB 驱动程序在遇到网络错误或者在 副本集 或 分片集群 中找不到健康的 主 节点时自动重试某些写入操作。
可重试写入需要副本集或分片集群,并且不支持独立实例
可重试写入需要支持文档级锁定的存储引擎,例如 WiredTiger 或 内存存储引擎。
客户端需要针对 MongoDB 3.6 或更高版本更新 MongoDB 驱动程序
写关注为 0 时发出的写入操作不可重试。
事务提交和中止操作是可重试的写入操作。如果提交操作或中止操作遇到错误,则不管 retryWrites 是否设置为 false,MongoDB 驱动程序都会重试该操作一次。
可重试读取
可重试读取允许 MongoDB 驱动程序在遇到某些网络或服务器错误时,自动重试某些读取操作一次。
与 MongoDB Server 4.2 及更高版本兼容的官方 MongoDB 驱动程序支持可重试读取。
只有连接到 MongoDB Server 3.6 或更高版本时,驱动程序才能重试读取操作。
文本搜索
mongoDB 的文本搜索功能支持对字符串内容执行文本搜索的查询操作。要执行文本搜索,MongoDB 会使用文本索引和 $text 操作符。参考
地理空间查询
读关注
通过有效使用写关注和读关注,您可以适当调整一致性和可用性保证的级别,例如等待更强的一致性保证,或者放松一致性要求以提供更高的可用性。
针对 MongoDB 3.2 或更高版本进行更新的 MongoDB 驱动程序支持指定读关注。
副本集和分片集群支持设置全局默认的读关注(read concern)。未指定显式读关注(read concern)的操作会继承全局默认的读关注(read concern)设置
| 等级 | 说明 |
|---|---|
| “local” | 查询从实例返回数据,不保证数据已写入副本集的多数成员 |
| “available” | 查询从实例返回数据,不保证数据已写入副本集的多数成员 读关注 “available” 不能与因果一致的会话和事务结合使用。 |
| “majority” | 该查询返回已被副本集多数成员确认的数据。即使失败,读取操作返回的文档也是持久性的。 |
| “linearizable” | 该查询返回的数据反映了在读取操作开始之前完成的所有成功的多数已确认的写入操作。该查询可能会等待并发执行的写入操作的数据复制到多数副本集成员之后,再返回结果。 |
| “snapshot” | 查询会返回最近某个特定时间点跨分片出现的多数提交数据。仅当事务以写关注 “snapshot” 提交时,读关注 “majority” |
写关注
写关注说明了 MongoDB 为针对独立运行的 mongod、副本集或分片集群的写入操作所请求的确认级别。在分片集群中,mongos 实例会将写关注传递给分片。
副本集和分片集群支持设置全局默认写关注。未指定显式写关注的操作会继承全局默认写关注设置。
{ w: <value>, j: <boolean>, wtimeout: <number> } |
w 选项,用于请求确认写入操作已传播到指定数量的 mongod 实例或带有指定标签的 mongod 实例。
j 选项,用于请求确认写入操作已写入磁盘上日志,以及
wtimeout 选项用于指定时间限制,防止写入操作无限期阻塞。
| w 值 | 说明 |
|---|---|
| “majority” | 要求确认写入操作已持久提交给计算出的多数承载数据的有投票权成员{ w: "majority" } |
<number> | 要求确认写入操作已传播到独立 mongod 或副本集中的主节点。{ w: 1 } |
<custom write concern name> | 要求确认写入操作已传播到满足 settings.getLastErrorModes 中所定义自定义写关注的 tagged 成员。 |
聚合操作
db.orders.aggregate( [ |
索引
索引支持在 MongoDB 中高效执行查询。如果没有索引,MongoDB 就必须扫描集合中的每个文档以返回查询结果。如果查询存在适当的索引,MongoDB 就可以使用该索引来限制其必须扫描的文档数。
索引可提高查询性能,但添加索引会影响写入操作的性能。对于写入读取率高的集合,由于每次插入操作都必须同时更新所有索引,因此会带来较高的索引成本。
MongoDB 在创建集合时会在 _id 字段上创建一个唯一索引。_id 索引可防止客户端插入两个具有相同 _id 字段值的文档。您无法删除此索引。
索引的默认名称是索引键和索引中每个键的方向(1 或 -1)的连接,使用下划线作为分隔符。例如,在 { item : 1, quantity: -1 } 上创建的索引的名称为 item1_quantity-1。
索引一旦创建便无法重命名。相反,您必须删除索引并使用新名称重新创建索引。
索引创建删除
创建索引 |
索引类型
- 单字段索引
- 复合索引
- 多键索引
多键索引收集数组中存储的数据并进行排序。
您无需显式指定多键类型。对包含数组值的字段创建索引时,MongoDB 会自动将该索引设为多键索引。 - 地理空间索引
- 文本索引
- 哈希索引
- 聚集索引
参考
索引属性
- 不分大小写的索引
- 隐藏索引 (Hidden Indexes)
- 部分索引
- 稀疏(Sparse)索引
- TTL 索引
- 唯一(Unique)索引
事务
- 启动事务
- 执行指定操作
- 提交结果(或在出错时中止)
示例:
|
Go
Mongo 为我们提供了各种语言的驱动库。使用go get进行下载即可使用。
go get go.mongodb.org/mongo-driver/mongo |
连接数据库
后序所有操作都会建立在这个基础之上,需要确保这一步的正确性。
package main |
插入文档
为了方便理解把当前模型用结构体表示出来
type Size struct { |
- 插入一条数据
|
- 使用结构体直接插入
type Canvas2 struct { |
canvas2 := Canvas2{ |
我们往往还会创建两方法实现 Canvas 和 Canvas2 之间的相互转换
func (c *Canvas) ToCanvas2() Canvas2 { |
- 插入多条数据
类比单挑插入可以很容易理解
|
查询
- 查找匹配条件的数据
result := coll.FindOne( |
- 批量查找
cursor, err := coll.Find(context.TODO(), bson.D{{"item", "canvas"}}) |
- 指定需要返回的字段
SetProjection中 0 表示不返回,1 表示返回
其中_id是默认返回项,需要显示禁止返回。
cursor, err := coll.Find( |
常用标记汇总
比较标记
标记 作用 $eq等于 $gt大于 $gte大于等于 $in包含 $lt小于 $lte小于等于 $ne不等于 $nin不包含 逻辑运算
标记 作用 $and并且 $not非 $nor都不满足 $or或 元素操作
标记 作用 $exists存在 $type类型 数组查询
标记 作用 示例 $all数组中包含所有列出元素 { tags: { $all: [ "ssl" , "security" ] } }$elemMatch数组中所有元素至少满足一个列规则 { results: { $elemMatch: { $gte: 80, $lt: 85 } } }$size限定数组长度 { field: { $size: 1 } }数组操作
标记 作用 示例 $addToSet加入集合 去重 { $addToSet: { colors:"mauve" } }$pop移队首或队尾 db.students.updateOne( { _id: 1 }, { $pop: { scores: -1 } } )$pull移除所有满足条件的 { $pull: { fruits: { $in: [ "apples", "oranges" ] }}}$push出入一条数据 { $push: { scores: { $each: [ 90, 92, 85 ] } } }$pullAll移除所有值匹配的 { $pullAll: { scores: [ 0, 5 ] } }$sort使用数组中对象字段排序 $sort: { score: 1 }查询结果操作
标记 作用 使用 $slice限定数组返回数量 { <arrayField>: { $slice: <number> } }更新操作
标记 作用 $currentDate当前日期 $inc+n $min取较小小值 $max取较大值 $mul乘法 $rename重命名字段 $set设置字段 $setOnInsert插入操作则设置字段值 $unset移除字段 其他
标记 作用 使用 $expr正则匹配 { $expr: { <expression> } }$mod取余 { field: { $mod: [ divisor, remainder ] } }
参考资料
- 本文作者: Tiny Beer
- 本文链接: https://tinybeer.github.io/2024/06/09/MongoDB学习笔记/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!
