重新定义OLTP数据库
On-Line Transaction Processing联机事务处理过程(OLTP)
-
什么是MongoDB
一个以Json为数据模型的文档数据库。
-
为什么叫文档数据库?
文档来自于”JSON Document", 并非我们一般理解的PDF,word…
- 主要用途
应用数据库,类似于Oracle, Mysql海量数据处理,数据平台。
- 主要特点
建模为可选
Json数据模型比较适合开发者
横向扩展可以支持很大数据量和并发
- 2018年开始支持事务
- 优点:
- 文档模型
- OLTP
- 复制集
- 通过原生分片支持横向扩展能力
- 索引支持
feature
面向开发者的易用+高效数据库
对象模型的数据库
灵活:快速响应业务变化
多行行:同一个集合中可以包含不同字段(类型))
原生的高可用和横向扩展能力(默认最少三个节点)
Replica Set-2 to 50个成员
MongoDB CURD Operations
Insert
如果集合不存在,自动创建集合.
Insert a Single Document
db.collection.insertOne()
db.inventory.insertOne(
{ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
insertOne 会返回插入文档的id属性 _id
Insert Multiple Documents
db.collection.insertMany()
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" } }
])
insertMany 会返回插入成功的id信息.
-
MongoDB会自动创建集合
-
插入语句会自动为没有包含
_id
属性的文档自动生成一个_id
属性用做改文档的主键信息。 -
所有的MongoDB的插入操作是原子性的。
Query
db.collection.find({})
db.inventory.find({})
等值查询
db.inventory.find({"qty":25})
In 查询
db.inventory.find({"qty":{$in:[50,100]}})
And
db.inventory.find({"qty":25},{"status":"A"})
Or
db.inventory.find({$or:[ {"qty":25},{"status":"A"}]})
Update
更新一条记录
db.inventory.updateOne(
{item:"paper"},
{
$set:{"size.uom":"cm",status:"P"},
$currentDate:{lastModified: true}
}
)
更新第一个item字段为”paper"的记录,修改它的size.uom 为 “cm",status改为:“P”,更新字段最后修改日期为当前日期。
更新多条记录
db.inventory.updateMany(
{"qty": {$lt: 50}},
{
$set:{"size.uom": "in", status:"P"},
$currentDate: {lastModified: true}
}
)
Delete
删除所有记录
db.inventory.deleteMany({})
有条件的删除记录
db.inventory.deleteMany({"status": "A"})
删除一条记录
db.inventory.deleteOne({status: "D"})
会删除所有匹配中的记录中的第一条记录
文本查找
Example data:
db.stores.insert(
[
{ _id: 1, name: "Java Hut", description: "Coffee and cakes" },
{ _id: 2, name: "Burger Buns", description: "Gourmet hamburgers" },
{ _id: 3, name: "Coffee Shop", description: "Just coffee" },
{ _id: 4, name: "Clothes Clothes Clothes", description: "Discount clothing" },
{ _id: 5, name: "Java Shopping", description: "Indonesian goods" }
]
)
创建索引
db.stores.createIndex({name: "text", description: "text"})
$text
通过$text 使用 text 索引 执行查找,并且在文本通过空格表示or连接符
db.stores.find( { $text: { $search: "java coffee shop" } } )
准确条件时的查询为了避免错误的将空格理解为or,通过 \ 转义
db.stores.find( { $text: { $search: "\"coffee shop\"" } } )
排除文本操作, 使用 - 表示不包含
db.stores.find( { $text: { $search: "java shop -coffee" } } )
排序
db.stores.find(
{ $text: { $search: "java coffee shop" } },
{ score: { $meta: "textScore" } }
).sort( { score: { $meta: "textScore" } } )
todo:
- 地理位置查询
- 读隔离,写确认
- 原子性和事务性
在执行写操作的时候,单记录的写操作是原子性的。如果写操作是多记录的,原子性也是体现在单条记录的操作上,
在一次写操作上,如果操作记录是涉及多条记录的情况,在整体的多行操作上不是原子性的。如果在执行当前写操作过程中,如果有其他线程同样执行写操作,就有可能会发生交叉操作的情况,从4.0版本开始,MongoDB支持在复制集上支持多记录上的事务性。在4.2版本开始支持分布式事务。
并发控制
- 通过在制定字段上创建唯一索引,具体实现如:
update() and Unique
and findAndModify() and Unique Index
Aggregation
Aggregation Framework是一个计算框架
管道(Pipleline)和步骤(Stage)
- 整个聚合运算过程称为pipleline,它是由多个步骤(Stage)组成的,每个管道:
- 接受一系列文档(原始数据)
- 每个步骤对这些文档进行一系列运算;
- 结果文档输出给下一个步骤;
聚合运算的基本格式
Pipleline = [$stage1, $stage2, #stage3, …]
db..aggregate(
Pipleline,
{options}
)
常见步骤
$match 过滤 lt gt and or…
$project 投影 map reduce …
$sort 排序 sum avg push addtoSet
$group 分组
s k i p / skip/ skip/limit 结果限制
$lookup 左外链接
$unwimd 展开数组
$bucket 分组统计
$facet 聚合bucket.
Demo:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJQlPbaU-1584866771729)(/Users/leejiliang/Library/Application Support/typora-user-images/image-20200322093608659.png)]
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
Optimization
- Projection
通过截取一个Collection的部分内容来优化查询结果。删除一些不必要的字段信息。
- Sequence
Replication
复制集作用
- 实现服务高可用
- 数据分发:将数据从一个区域复制到另外一个区域,减少另一个区域的读延迟
- 读写分离:不同类型的压力分散在不同的节点上执行
- 异地容灾:在数据中心故障时快速切换到其他服务器
实现的原理
- 数据写入时将数据迅速复制到另一个独立节点上
- 在接受写入的节点发生故障时自动选举出一个新的节点代替主节点
典型复制集结构
三个以上具有投票权的节点组成典型复制集,包括:
- 一个主节点(PRIMARY) : 接受写入操作和选举时投票
- 多个从节点(SECONDARY) : 复制主节点上的新数据和选举时负责投票
- Arbiter(选举节点)
数据复制过程
-
Mongo会在主节点发生变更时,将变更操作记录下来(类似Mysql binLog),记录称为:oplog.
-
从节点通过不断的获取主节点上oplog的变动信息,在从节点上执行以保证跟主节点保持数据一致。
选举过程
-
具有投票权的节点之间两两发送心跳,保持节点状态被可知;
-
5次心跳未收到时判断为节点故障
-
如果故障的是主节点,从节点会发起选举,选举出新的节点
-
如果是从节点,不会发起选举
-
选举是基于(RAFT一致性算法)实现,选举成功的必要条件是(大多数投票节点存活)
-
复制集中最多可以有50个节点,但是选举节点最多有7个。
影响选举的因素
- 整个集群必须有大多数节点存活
- 被选举为主节点的节点要求:
- 能够与多数节点建立连接
- 具有比较新的oplog
- 如果配置了优先级,优先选择优先级比较高的节点
复制集节点可选配置项
-
是否具有投票权
-
priority 被选举为主节点的优先级, 为0时不能被选举为主节点
-
hidden 用于复制数据,但是对应用不可见,可以拥有投票权,优先级必须设置为0,被用来做安全备份
- slaveDelay 延迟复制主节点数据,和主节点保持一点的时间差,用于防止误操作。
Replication 搭建
- 创建三个数据文件夹
sudo mkdir /usr/local/mongodb/data/db{1,2,3}
- 为3个mongoDB准备三份配置文件
systemLog:
destincation: file
path: /usr/local/mongodb/data/db1/mongod.log # log path
storage:
dbPath: /usr/local/mongodb/data/db1 # data directory
net:
bindIp: 0.0.0.0
port: 28017 # port
replication:
replSetName: rs0
processManagement:
fork: true
需要分别为每个配置文件修改日志路径,数据文件路径,和端口号信息
- 启动
sudo mongod -f db1/mongod.conf
- 查看启动结果
ps -ef | grep mongod
- 配置复制集
-
Mongo --port 28107
rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:28017" },{ _id: 1, host: "localhost:28018" },{ _id: 2, host: "localhost:28019" }] })
- 查看复制集状态:
# rs.status()
在从节点上执行查询操作时提示:
"errmsg" : "not master and slaveOk=false"
, 通过执行指令:rs.slaveOk()
即可解决.
参考:
MonngoDB官网 https://docs.mongodb.com/manual/
极客时间: MongoDB高手课