MongoDB CRUD操作:批量写操作
文章目录
- [MongoDB CRUD操作:批量写操作](#MongoDB CRUD操作:批量写操作)
MongoDB提供了批量执行写入操作的能力,但批量写入操作只影响单个集合, MongoDB允许应用程序确定批量写入操作所需的可接受的确认级别。
db.collection.bulkWrite()
方法支持批量插入、更新和删除的操作。当然,通过 db.collection.insertMany()
方法也可以进行批量插入的操作。
关于批量操作的顺序
批量写入操作可以是有序的,也可以是无序的。通过操作的有序列表,MongoDB串行执行操作。如果在处理其中一个写操作期间发生错误,MongoDB 将返回,而不处理列表中任何剩余的写操作。
对于无序列表的操作,MongoDB可以并行执行操作,但不能保证这种行为。如果在处理其中一个写操作的过程中发生错误,MongoDB将继续处理列表中剩余的写操作。
在分片集合上执行有序操作列表通常会比执行无序列表慢,因为使用有序列表时,每个操作都必须等待前一个操作完成。
默认情况下,bulkWrite()
执行有序操作,如果要指定无序写入操作,可以选项文档中设置ordered: false
。
bulkWrite()支持的方法
bulkWrite()
支持下面的写操作:
insertOne
updateOne
updateMany
replaceOne
deleteOne
deleteMany
所有的写操作都作为数组中的文档传递给bulkWrite()
举例
使用下面的脚本创建pizzas
集合:
js
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 }
] )
下面的bulkWrite()
示例在pizzas
集合上运行:
- 使用
insertOne
添加两个文档 - 使用
updateOne
更新一个文档 - 使用
deleteOne
删除一个文档 - 使用
replaceOne
替换一个文档
js
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 )
}
执行完成后输出已完成操作的摘要信息:
js
{
acknowledged: true,
insertedCount: 2,
insertedIds: { '0': 3, '1': 4 },
matchedCount: 2,
modifiedCount: 2,
deletedCount: 1,
upsertedCount: 0,
upsertedIds: {}
}
向分片集合批量插入的策略
大量插入操作(包括初始数据插入或常规数据导入)可能会影响分片集群的性能。对于批量插入,可考虑以下策略:
预分割集合
如果分片集合为空,则该集合只有一个初始块,该块驻留在单个分片上,MongoDB必须花时间接收数据、创建拆分并将拆分块分发到可用分片。为了避免这种性能成本,可以预先拆分集合。
无序写入 mongos
要提高分片集群的写入性能,可以使用bulkWrite()``,并将可选参数ordered
设置为false
。 mongos可以尝试同时将写入发送到多个分片。对于空集合,首先按照分片集群中的分割块中的描述预先分割集合。
避免单调节流
如果分片键在插入期间单调增加,则所有插入的数据都会到达集合中的最后一个块,该块将始终位于单个分片上。因此,集群的插入容量永远不会超过单个分片的插入容量。
如果插入量大于单个分片可以处理的量,并且无法避免单调递增的分片键,则建议对应用程序进行以下修改:
- 反转片键的二进制位。这保留了信息并避免将插入顺序与递增的值序列相关联。
- 交换第一个和最后一个 16 位字以"随机"插入。
以下示例采用 C++ 语言,交换生成的 BSON ObjectId 的前导和尾随 16 位字,以便它们不再单调递增。
c++
using namespace mongo;
OID make_an_id() {
OID x = OID::gen();
const unsigned char *p = x.getData();
swap( (unsigned short&) p[0], (unsigned short&) p[10] );
return x;
}
void foo() {
// 创建一个对象
BSONObj o = BSON( "_id" << make_an_id() << "x" << 3 << "name" << "jane" );
}