今天我们继续讨论
4 基于基本操作的复杂更新
5 如何利用传统数据库经常谈到的,两阶段提交协议在MongoDB中应用乐观更新的模式
在说这个部分前我们先说说 数组
MongoDB 中在在进行文档设计的时候,必须要提到一点,数组。在传统数据库中基本上很少提到数组,但是在MongoDB的设计中数组是必须要会的一个属性或者说一个“文档”设计当中的要点。
这里我们先总结,然后再举例
1 数组在MongoDB 的主要作用可以理解为解决一对多的关系描述,利用数组来模拟出高效的多个事务归属于一个事务的关系。
2 数组灵活,数组中可以包含不同数据类型的元素,或其他的文档或数组,可以表达的一对多的关系可以更加的复杂。
3 数组的更新和删除元素都比较的简单,通过 PUSH ,PULL,SET 进行元素的增删设置等
这里我们举几个例子
1 产品说明
{ "_id": ObjectId("..."), "title": "沃尔沃S60", "介绍内容": "北欧奢华的安全座驾B级车标杆", "特性": ["无甲醛", "自动避让", "坚固车身", "环保"] }
上面的特性部分就是数组,如果这放到了传统数据库这将无法处理,比如问,有多少车有环保的特性,此时你只能通过 select * from table where 特性 like '%环保%' or '环保%' or '%环保'; 来进行查询。
db.cars.find({ "特性": "环保" })
db.cars.find({ "特性": { $in: ["环保"] } })
db.cars.find({ "特性": { $regex: "^环保" } })
而这些查询中我们可以统一为特性建立一个索引
db.cars.createIndex({ "特性": 1 })
2 订单和订单项
{
"orderId": "order456",
"customerName": "Bob",
"orderItems": [
{ "product": "Laptop", "quantity": 1 },
{ "product": "Mouse", "quantity": 2 }
],
"orderDate": "2025-01-08"
}
这是一个典型的案例,上面的orderItems是一个数组,通过通过数组中利用嵌套本身作为数组的元素。查询的方式也比较简单,通过对元素本身的值进行查询即可。
db.orders.find({
"orderItems.product": "Laptop"
});
以上的使用方式在数组中使用平铺数据或嵌套等可以利用在持久的一对多的关系中,同时需要注意,数组的数据不是高频应该进行数据的更新或清理的,同时数组中的元素也不宜过度使用。
简单说完数组,我们继续说数据的更新,在MongoDB中的设计也可以根据具体的数据更新的部分进行设计,
1 需要原子更新的相关数据,尽量将他嵌入同一个文档中
2 经常要更新的数据,可以和不经常更新的数据进行分离,避免经常更新导致的性能问题,这里可以使用引用的方式将不经常更新的数据作为查询的主体,通过引用要更新的部分,一次通过查询获取要更新的文档,且一次性更新。
3 如果需要通过引用进行数据更新,注意是否对数据的更新和读取有一致性的要求,如果有强一致性的要求,则应该将数据放置在一个文档中,而不是通过引用的方式。
4 这点是MongoDB独有的,我们可以通过版本控制来进行,比如我们把更新数据变为插入数据,通过在文档中增加版本这个标签,来完全规避更新数据,而通过insert数据加标签的方式来进行
5 频繁更新数据的部分,应考虑减少使用数组的可能性或者控制更新数据的数组的大小,应该尽量的小。
6 通过读写分离的方案,尽量将对于数据的时效性不敏感的查询放置在从库查询。
这里补充一个特殊的方案针对大量的数据更新和提高更新的性能的方案
首先如果需要一次性更新数量较多的文档,可以将更新设置为什么 writeConcern {w:0} ,在这样的情况下,更新数据时MongoDB的性能是最高的。
在操作都更新完毕后,直接对更新的数据进行查询因为有条件的查询是较快的,在确认更新的操作都完结后,可以直接通过 findAndModify 操作来进行对预先设计的更新标志位进行查询和更新,以此作为整体数据更新的成功标记。
通过这样的方法可以快速的对数据进行更新并且提高的性能最高,这样方式
优点: 提高性能: 第一阶段不等待写入确认,可以提高更新性能。 模拟两阶段提交: 通过记录和回滚操作,可以模拟传统数据库中的两阶段提交协议,确保数据一致性。
缺点: 实现复杂: 需要额外的集合和操作来记录和回滚更新操作。 无法保证完全隔离: 在第一阶段和第二阶段之间,其他操作可能会读取到未提交的数据。
以上方式实际上是在模拟两阶段提交。
个人理解,大部分情况MongoDB的数据更新如同面条,酱汁和好吃的都挂在面条外面,但我们也可以模拟传统数据库的数据更新方式,将数据更新包装成事务的方式,进行统一的更新和确认,如同肠粉,馅料是在里面的,但重点是,都好吃。
本文分享自 AustinDatabases 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!