MongoDB(文档数据库)的简单使用
MongoDB最好的学习资料就是他的官方文档:SQL 到 MongoDB 的映射图表 - MongoDB 手册 v8.0
1.MongoDB CRUD操作
1.1Insert操作
基本方法:
|
|
注意:插入操作针对的是单个集合。MongoDB 中的所有写入操作在单个文档级别都具有原子性。
示例:
1.2Select操作
基本方法:
|
示例:
1.3Update操作
基本方法:
|
|
|
在 MongoDB 中,更新操作针对的是单个集合。MongoDB 中的所有写入操作在单个文档级别都具有原子性。
示例:
1.4Delete操作
基本方法:
|
|
在 MongoDB 中,删除操作针对的是单个集合。MongoDB 中的所有写入操作在单个文档级别都具有原子性。
示例:
2.MongoDB 分片
2.1概念
分片是一种跨多台机器分布数据的方法。MongoDB 使用分片来支持超大数据集和高吞吐量操作的部署。
存在大型数据集或高吞吐量应用程序的数据库系统可能对单个服务器的容量构成挑战。例如,较高的查询速率可能会耗尽服务器的 CPU 容量。大于系统 RAM 的工作集大小会对磁盘驱动器的 I/O 容量造成压力。
因此,有两种方法可解决系统增长问题:垂直扩展和水平扩展。
(1)Vertical Scaling(垂直扩展)涉及增大单个服务器的容量,例如使用更强大的 CPU、添加更多 RAM 或增加存储空间量。可用技术所存在的限制可能会导致单个机器对给定工作负载来说不够强大。此外,基于云的提供商存在基于可用硬件配置的硬上限。因此,垂直扩展存在实际的最大值。
(2)Horizontal Scaling(横向(水平)扩展)涉及将系统数据集和负载划分到多个服务器,以及按需增加服务器以提高容量。虽然单个机器的总体速度或容量可能不高,但每个机器均可处理总体工作负载的一部分,因此可能会比单个高速、高容量服务器提供更高的效率。扩展部署的容量只需按需添加额外的服务器,而这可能会比单个机器的高端硬件的整体成本更低。但代价在于它会增大部署的基础设施与维护的复杂性。
MongoDB 支持通过分片进行水平扩展。
2.2分片集群
描述了分片集群内各组件之间的交互:
MongoDB分片集群由以下组件构成:
(1)分片:每个分片都包含分片数据的一个子集。
(2)mongos:mongos
充当查询路由器,在客户端应用程序和分片集群之间提供接口。
(3)配置服务器:配置服务器会存储集群的元数据和配置设置。配置服务器必须部署为副本集 (CSRS)。
综上所述:一个基本的Mongodb集群需要配置MASTER节点-SLAVE节点-路由节点-仲裁节点。
2.3分片键/数据段
2.3.1分片键
作用:MongoDB 使用分片键在分片之间分发集合的文档。 分片键由文档中的一个或多个字段组成。
分片集合中的文档可能缺少分片键字段。跨分片分发文档时,缺少的分片键字段将视为具有 null 值,但在路由查询时则不会。
注意:
-
从在MongoDB 5.0 开始,您可以通过更改集合的分片键对集合重新分片。
-
您可以通过向现有分片键添加后缀字段或字段来优化分片键。
(1)分片键索引
要对已填充的集合进行分片,该集合必须具有以分片键开头的索引。对空集合进行分片时,如果该集合还没有指定分片键的适当索引,MongoDB 会创建支持索引。请参阅分片键索引。
(2)分片键策略
分片键的选择会影响分片集群的性能、效率和可扩展性。 具有最佳硬件和基础架构的集群可能会因为选择分片键而遇到瓶颈。 分片键及其后备索引的选择也会影响集群可以使用的分片策略。
2.3.2数据段
MongoDB 将数据分片为数据段。每个数据段都有一个基于分片键、包含下限且不包含上限的范围。
2.3.3负载均衡器和均匀数据分布
为了实现数据在集群中所有分片上的均匀分布,负载均衡器会在后台运行,以便在各分片之间迁移范围。
2.4分片的优点
(1)读取/写入
MongoDB 在分片集群中的分片之间分配读写工作负载,支持每个分片处理集群操作的子集。通过添加更多的分片,读写工作负载都可以在集群中横向扩展。
对于包含分片键或复合分片键前缀的查询,mongos 可将查询定向到特定分片或一组分片。这些有针对性的操作通常比向集群中的每个分片进行广播更为有效。
(2)存储容量
分片将数据分布在集群中的分片上,从而允许每个分片包含整个集群数据的子集。随着数据集的增长,更多的分片会增加集群的存储容量。
(3)高可用性
按副本集部署配置服务器和分片,可提高可用性。
即使一个或多个分片副本集变为完全不可用,分片集群仍可继续执行部分读取和写入操作。换言之,即便无法访问不可用分片上的数据,针对可用分片的读取或写入仍可成功完成。
注意:
需要对分片集群基础架构的需求和复杂性进行仔细规划、执行和维护。
虽然您可在后续对集合重新分片,但请务必仔细考虑分片键的选择,以免出现可扩展性与性能问题。
3.SQL到MongoDB的映射表
下表列出各种SQL术语和概念以及相应的MongoDB术语和概念
传统关系型数据库中SQL术语/概念 | NoSQL型MongoDB数据库术语/概念 |
database | database |
数据表(table) | 集合(collection) |
行 | 文档或BSON文档 |
列 | 字段 |
索引(index) | 索引(index) |
表连接 | $lookup,嵌入式文档 |
主键 | 主键 |
指定任何唯一列或列组合作为主键 | 在MongoDB中,主键会自动设置为_id字段 |
聚合(例如分组依据) | 聚合管道(请参阅 SQL 聚合映射图表) |
SELECT INTO NEW_TABLE | $out( 请参阅SQL 聚合映射图表) |
MERGE INTO TABLE | $merge(请参阅 SQL 聚合映射图表) |
UNION ALL | $unionWith |
事务 | 事务(在许多场景中,非规范化数据模型(嵌入式文档和数组),而不是多文档事务,将继续是数据和使用案例的最佳选择。换言之,对于许多场景,适当地建模数据将最大限度地减少对多文档事务的需求) |
3.1可执行程序的对比
Mongodb | MySQL | Oracle | |
数据库服务 | mongod | mysqld | oracle |
数据库客户端 | mongosh | mysql | sqlplus |
4.SQL语句之间的对比
如下代码表示在MongoDB中的一个集合中一条数据记录的状态;
示例:
{_id: ObjectId("509a8fb2f3f4948bd2f983a0"),user_id: "abc123",age: 55,status: 'A'
}
4.1创建和更改
下表列出了与表级动作相关的各种SQL语句以及对应的MongoDB语句。
(1)SQL模式语句
创建表:
CREATE TABLE people (id MEDIUMINT NOT NULLAUTO_INCREMENT,user_id Varchar(30),age Number,status char(1),PRIMARY KEY (id)
)
修改表:
ALTER TABLE people
ADD join_date DATETIME
ALTER TABLE people
DROP COLUMN join_date
创建索引:
CREATE INDEX idx_user_id_asc
ON people(user_id)
CREATE INDEXidx_user_id_asc_age_desc
ON people(user_id, age DESC)
删除表:
DROP TABLE people
(2)对应上述SQL语句的MongoDB语句
创建集合
注意:如果该集合当前不存在,则插入操作将创建该集合。
a.隐式的创建一个集合
在第一个 insertOne() 或 insertMany() 操作上隐式创建。如果未指定 _id
字段,则会自动添加主键 _id
。
db.people.insertOne( {user_id: "abc123",age: 55,status: "A"} )
b.显示的创建一个集合
db.createCollection("people")
修改集合
集合并不描述或强制执行其文档的结构;也就是说,集合层面上不会有结构变化。
不过,在文档级别,updateMany() 操作可以使用 $set 操作符将字段添加到现有文档中。
db.people.updateMany({ },{ $set: { join_date: new Date() } }
)
集合并不描述或强制执行其文档的结构;也就是说,集合层面上不会有结构变化。
不过,在文档级别,updateMany() 操作可以使用 $unset 操作符从文档中删除字段。
db.people.updateMany({ },{ $unset: { "join_date": "" } }
)
创建索引
db.people.createIndex( { user_id: 1 } )
db.people.createIndex( { user_id: 1, age: -1 } )
删除集合
db.people.drop()
4.2Insert
(1)传统SQL
INSERT INTO people(user_id,age,status)
VALUES ("bcd001",45,"A")
(2)MongoDB
db.people.insertOne({ user_id: "bcd001", age: 45, status: "A" }
)
4.3Select
(1)传统SQL
(1)SELECT * FROM people(2)SELECT id,user_id,status FROM people(3)SELECT user_id, status FROM people(4)SELECT * FROM people WHERE status = "A"(5)SELECT user_id, status FROM people WHERE status = "A"(6)SELECT * FROM people WHERE status != "A"(7)SELECT * FROM people WHERE status = "A" AND age = 50(8)SELECT * FROM people WHERE status = "A" OR age = 50(9)SELECT * FROM people WHERE age > 25(10)SELECT * FROM people WHERE age < 25(11)SELECT * FROM people WHERE age > 25 AND age <= 50(12)SELECT * FROM people WHERE user_id like "%bc%"(13)SELECT * FROM people WHERE user_id like "bc%"(14)SELECT * FROM people WHERE status = "A" ORDER BY user_id ASC(15)SELECT * FROM people WHERE status = "A" ORDER BY user_id DESC(16)SELECT COUNT(*) FROM people(17)SELECT COUNT(user_id) FROM people(18)SELECT COUNT(*) FROM people WHERE age > 30(19)SELECT DISTINCT(status) FROM people(20)SELECT * FROM people LIMIT 1(21)SELECT * FROM people LIMIT 5 SKIP 10(22)EXPLAIN SELECT * FROM people WHERE status = "A"
(2)MongoDB
(1)db.people.find()(2)db.people.find({ },{ user_id: 1, status: 1 }
)(3)db.people.find({ },{ user_id: 1, status: 1, _id: 0 }
)(4)db.people.find({ status: "A" }
)(5)db.people.find({ status: "A" },{ user_id: 1, status: 1, _id: 0 }
)(6)db.people.find({ status: { $ne: "A" } }
)(7)db.people.find({ status: "A",age: 50 }
)(8)db.people.find({ $or: [ { status: "A" } , { age: 50 } ] }
)(9)db.people.find({ age: { $gt: 25 } }
)(10)db.people.find({ age: { $lt: 25 } }
)(11)db.people.find({ age: { $gt: 25, $lte: 50 } }
)(12)db.people.find( { user_id: /bc/ } )
或
db.people.find( { user_id: { $regex: /bc/ } } )(13)db.people.find( { user_id: /^bc/ } )
或
db.people.find( { user_id: { $regex: /^bc/ } } )(14)db.people.find( { status: "A" } ).sort( { user_id: 1 } )(15)db.people.find( { status: "A" } ).sort( { user_id: -1 } )(16)db.people.count()
或
db.people.find().count()(17)db.people.count( { user_id: { $exists: true } } )
或
db.people.find( { user_id: { $exists: true } } ).count()(18)db.people.count( { age: { $gt: 30 } } )
或
db.people.find( { age: { $gt: 30 } } ).count()(19)db.people.aggregate( [ { $group : { _id : "$status" } } ] )
或,对于不超过 BSON 大小限制的非重复值集
db.people.distinct( "status" )(20)db.people.findOne() 或 db.people.find().limit(1)(21)db.people.find().limit(5).skip(10)(22)db.people.find( { status: "A" } ).explain()
4.4Update
(1)传统SQL
UPDATE people
SET status = "C"
WHERE age > 25UPDATE people
SET age = age + 3
WHERE status = "A"
(2)MongoDB
db.people.updateMany({ age: { $gt: 25 } },{ $set: { status: "C" } }
)db.people.updateMany({ status: "A" } ,{ $inc: { age: 3 } }
)
4.5Delete
(1)传统SQL
DELETE FROM people
WHERE status = "D"DELETE FROM people
(2)MongoDB
db.people.deleteMany( { status: "D" } )db.people.deleteMany({})