学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第76篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。
概述
Mongodb提供了针对单一集合写操作批量执行的方法。在批量写操作当中,Mongodb也允许用户自由定义数据提交的方式。通过db.collection.bulkWrite()方法,用户能够对单一集合进行数据插入,更新和删除操作 。当然, 方法db.collection.insertMany()也是一种批量写入操作。
批量写操作的顺序
用户定义的批量操作,可以是顺序执行的,也可以不按照顺序执行。
在顺序执行操作当中,Mongodb按照用户定义的批量操作序列,一步一步的执行。当某一个写操作出现错误时,mongdb会退出当前执行序列,不再执行后续的操作。而在非顺序执行操作当中,Mongodb并行执行用户定义的每一个操作。在非顺序执行操作当中,任意一个操作出错不会影响其他操作的执行。
在分片集合当中,顺序执行操作会比非顺序执行操作慢。因为需要等待前面的步骤完成。
bulkWrite()操作,默认是顺序执行每一个操作。用户如果需要指定非顺序执行,需要在options中定义{ordered: false}
支持批量写入的方法
bulkWrite支持下面的几个方法, 每一个方法都按照文档的形式 定义在bulkWrite操作的过程数据中。
-
- insertOne
- updateOne
- updateMany
- replaceOne
- deleteOne
- deleteMany
应用
构建pizza文档并插入数据
db.pizzas.insertMany([{
_id: 0, type: "pepperoni", size: "small", price: 4
},{
_id: 1, type: "cheese", size: "medium", price: 7
},{
_id: 2, type: "vegan", size: "large", price: 8
}])
构建批量数据更新语句,要求完成下面几个动作
-
向集合中插入两条新数据
-
更新cheese文档的价格
-
删除pepperoni
-
将vegan替换成新的文档tofu
try {
db.pizzas.bulkWrite( [
{ insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } },
{ insertOne: { document: { _id: 4, type: "sausage", size: "large", price: 10 } } },
{ updateOne: {
filter: { type: "cheese" },
update: { $set: { price: 8 } }
} },
{ deleteOne: { filter: { type: "pepperoni"} } },
{ replaceOne: {
filter: { type: "vegan" },
replacement: { type: "tofu", size: "small", price: 4 }
} }
] )
} catch( error ) {
print( error )
}
分片集中批量写入策略
在分片集中,大量的写入操作包括数据初始化,导入数据等可能会影响分片集的性能。因此,批量写入操作,可以考虑下面的策略
提前分片
mongodb中,空数据集只有一个初始数据块,放在单个分片当中。插入数据时,mongodb需要在接收数据,创建数据分块,将数据分块写入分片上消耗大量的时间。为了避免数据分块消耗的时间,用户可以提前将数据分好。
非顺序写入
为了在分片集中提高写入效率 ,用户可以将bulkWrite()方法的ordered参数设置为false。这样mongos可以尝试同时向多个分片写入数据。
避免在分片集中使用单调主键
如果片键在一次插入过程中单调递增,那么所有插入的数据都会进入集合的最后一个块,而这个块总是会出现在一个片上。因此,集群的插入容量永远不会超过该单个分片的插入容量。如果插入数据量大于单个分片所能处理的数据量,并且无法避免片键的单调递增,那么可以考虑对应用进行以下修改。反转片键的二进制位。这样可以保留信息,并避免将插入顺序与值的递增顺序关联起来。交换第一个和最后一个16位的单词来"打乱"插入操作。