Hi~朋友,关注置顶防止错过消息
MongoDB提供了批量写入的能力,包含批量插入、更新和删除,函数如下:
db.collection.bulkWrite(
[ <operation 1>, <operation 2>, ... ],
{
writeConcern : <document>,
ordered : <boolean>
}
)
- operation是一个批量更新操作的数组,取值有insertOne,deleteOne,updateOne,deleteMany,updateMany,replaceOne
- writeConcern:写关注的级别
- ordered:是否顺序执行,如果为true顺序执行遇到错误停止执行后续操作,如果为false,执行过程遇到错误忽略并继续执行后续的任务,默认值false
insertOne操作
db.collection.bulkWrite( [
{ insertOne : { "document": <document>} }
] )
updateOne操作
db.collection.bulkWrite( [
{ updateOne :
{
"filter": <document>,
"update": <document or pipeline>,
"upsert": <boolean>,
"collation": <document>,
"arrayFilters": [ <filterdocument1>, ... ],
"hint": <document|string>
}
}
] )
- filter:用来过滤需要更新的数据
- update:更新操作,这里可以是只包含update operator的document 或者聚合pipeline
- upsert:是否做更新插入操作
- collation:指定排序规则
- arrayFilters:数组筛选器,指定数组中要更新的元素的的条件
- hint:指定更新要使用的索引,如果索引不存在,写入会报错
replaceOne操作
db.collection.bulkWrite([
{ replaceOne :
{
"filter": <document>,
"replacement": <document>,
"upsert": <boolean>,
"collation": <document>,
"hint": <document|string>
}
}
] )
- filter:用来过滤需要替换的数据
- update:替换操作,这里是不包含update operators的Document
- upsert:是否做更新插入操作
- collation:指定排序规则
- hint:指定更新要使用的索引,如果索引不存在,写入会报错
deleteOne操作
db.collection.bulkWrite([
{ deleteOne : {
"filter": <document>,
"collation": <document>// Available starting in 3.4
} }
] )
- filter:用来过滤需要删除的数据
- collation:指定排序规则
BulkWrite每组最大的操作数量不能超过maxWriteBatchSize(默认值是100000)的限制, 如果超过客户端程序会将他们拆分成多个小的批操作,同时如果批操作的操作太多,MongoDB会将错误消息截断成空字符串。
在分片集合上执行有序批操作会比普通集合更加耗时。
Capped集合限制
- updateOne和updateMany操作,如果更新增加了文档的大小会抛出异常
- replaceOne操作,如果新的文档大小比原始文档大,则会抛出异常
- deleteOne和deleteMany操作不可以在Capped Collection使用,否则会抛出异常
Time Series集合限制
在时序集合上,BulkWrite操作只支持insertOne批操作,其他的都会抛出异常。
事务外的BulkWrite异常处理
在不考虑Write Concern报错下,错误会被写入writeErrors字段,有序操作在错误后停止,会写入第一个碰到的错误,无序操作则会写入批操作中的每个错误,一旦有错误发生,结果就不会显示插入_id的值,而是变成插入成功的数量。
事务内的BulkWrite异常处理
如果BulkWrite使用事务,write concern和事务不能产生冲突,并且不管Bulk是有序还是无序操作,只要碰到错误,整个批操作都会被回滚。
数据批量插入集合的建议
- 预拆分集合,对于分片集合来说,假设集合为空的,该集合那就只有一个初始化块存在于一个单一分片上,MongoDB接收到数据以后需要对块进行拆分,并且分配到可用的分片上,为了提高性能我们可以预先拆分集合(后面单独说)
- 尽量使用无序的BulkWrite操作
- 避免单调递增,假设分片键是递增的,那么所有的数据插入都会进入集合的最后一个块,因此该集群的插入能力始终受到最后一个分片的限制,可以通过以下方法来进行优化:1.反转分片键的二进制位;2.交换分片键的前16位和后16 位