批量插入数据,主键冲突报错,并继续执行后面操作
ordered :
定义
db.collection.bulkWrite()
提供可控执行顺序的批量写操作。
语法格式如下:
1
2
3
4
5
6
7
|
db.collection.bulkWrite(
[
{
writeConcern :
ordered :
}
)
|
参数 | 类型 | 描述 |
---|---|---|
operations | array | bulkWrite() 写操作的数组。支持操作:insertOne、updateOne、updateMany、deleteOne、deleteMany、replaceOne |
writeConcern | document | 可选, write concern 文档,省略则使用默认的 write concern。 |
ordered | boolean | 可选,表示mongod实例有序还是无序执行操作。默认值true。 |
方法返回值:
-
操作基于 write concern 运行则 acknowledged 值为true,如果禁用 write concern 运行则 acknowledged 值为false。
-
每一个写操作数。
-
成功 inserted 或 upserted文档的 _id 的组数。
行为
bulkWrite() 接收一个写操作的数组然后执行它们中的每一个。默认是有序的执行。
写操作
insertOne
插入单个文档到集合中。
1
2
3
|
db.collection.bulkWrite( [
{ insertOne : {
"document"
:
] )
|
updateOne 及 updateMany
updateOne 更新集合中 filter 匹配的单个文档。如果匹配到多个文档 updateOne 仅更新第一个匹配到的文档。
1
2
3
4
5
6
7
8
9
|
db.collection.bulkWrite( [
{ updateOne :
{
"filter"
:
"update"
:
"upsert"
:
}
}
] )
|
updateMany 更新集合中所有匹配到的文档。
1
2
3
4
5
6
7
8
9
|
db.collection.bulkWrite( [
{ updateMany :
{
"filter"
:
"update"
:
"upsert"
:
}
}
] )
|
对字段的更新操作例如 $set 、$unset 、$rename等。
默认情况 upsert 为 false。
replaceOne
replaceOne 替换集合中 filter 匹配到的单个文档。如果匹配到多个文档 replaceOne 只会替换一个匹配到的文档。
1
2
3
4
5
6
7
8
9
|
db.collection.bulkWrite([
{ replaceOne :
{
"filter"
:
"replacement"
:
"upsert"
:
}
}
] )
|
replacement 字段中不能包含 update 操作。
默认情况 upsert 为 false。
deleteOne 及 deleteMany
deleteOne 删除集合中 filter 匹配到的单个文档。如果匹配到多个文档 deleteOne 只会删除一个匹配到的文档。
1
2
3
|
db.collection.bulkWrite([
{ deleteOne : {
"filter"
:
] )
|
deleteMany 删除集合中 filter 匹配到的所有文档。
1
2
3
|
db.collection.bulkWrite([
{ deleteMany : {
"filter"
:
] )
|
_id 字段
如果文档未指定 _id 字段,则mongod会在 insert 或 upsert 文档之前添加 _id 字段并指定唯一的ObjectId。 大多数驱动程序会创建一个ObjectId并插入到 _id 字段,但如果驱动程序或应用程序没有,mongod将创建并填充 _id。
如果文档包含 _id 字段,则 _id 值在集合中必须是唯一的,以避免重复键错误。
更新或替换操作不能指定与原始文档不同的 _id 值。
执行操作
ordered 参数指定 bulkWrite() 是否有序执行,默认情况下是有序执行。
含有6个操作的 bulkWrite() 代码如下:
1
2
3
4
5
6
7
8
9
10
|
db.collection.bulkWrite(
[
{ insertOne :
{ updateOne :
{ updateMany :
{ replaceOne :
{ deleteOne :
{ deleteMany :
]
)
|
默认情况下 ordered : true ,每个操作将会有序的执行,从第一个insertOne 到最后一个deleteMany 顺序执行。
应用程序不依赖操作执行顺序是,可以设置 ordered 为 false ,此时mongod 会重新排序操作来提高性能。
含有6个操作无序的 bulkWrite() 代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
db.collection.bulkWrite(
[
{ insertOne :
{ updateOne :
{ updateMany :
{ replaceOne :
{ deleteOne :
{ deleteMany :
],
{ ordered :
false
}
)
|
对于ordered:false,操作结果可能会有所不同。 例如,deleteOne或deleteMany 删除的文档可能会变多或变少,具体取决于deleteOne或deleteMany 是在insertOne,updateOne,updateMany或replaceOne操作之前或之后的运行。
每组操作最多可以有1000次操作。 如果一个组超过此限制,MongoDB会将该组划分为1000或更小的组。 例如,如果队列包含2000个操作,MongoDB将创建2个组,每个组具有1000个操作。
大小和分组机制是内部的执行细节,在将来的版本中可能会有所变化。
在分片集合上执行有序操作通常比执行无序操作慢,因为对于有序,每个操作必须等待上一个操作完成。
固定集合(Capped Collections)
bulkWrite() 写操作在固定集合上使用有所限制。
-
updateOne 和 updateMany 更新时增加了被修改文档的大小将会抛出 WriteError
-
replaceOne 操作替换的文档比之前的文档大会抛出 WriteError
-
deleteOne 和 deleteMany 操作在固定集合上会抛出 WriteError
操作处理(Error Handling)
bulkWrite() 在错误发生时会抛出 BulkWriteError 异常。
排除Write Concern错误,有序操作在发生错误后停止,及无序操作继续处理队列中的剩余写入操作。
Write Concern 错误显示在 writeConcernErrors字段中,而所有其他错误都显示在writeErrors字段中。 如果遇到错误,则显示成功写入操作的数量而不是插入的_id值。 有序操作显示遇到的单个错误,而无序操作显示数组中的每个错误。
实例
批量写
characters 集合包含以下文档:
1
2
3
|
{
"_id"
: 1,
"char"
:
"Brisbane"
,
"class"
:
"monk"
,
"lvl"
: 4 },
{
"_id"
: 2,
"char"
:
"Eldon"
,
"class"
:
"alchemist"
,
"lvl"
: 3 },
{
"_id"
: 3,
"char"
:
"Meldane"
,
"class"
:
"ranger"
,
"lvl"
: 3 }
|
bulkWrite() 在集合上执行批量操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
try
{
db.characters.bulkWrite(
[
{ insertOne :
{
"document"
:
{
"_id"
: 4,
"char"
:
"Dithras"
,
"class"
:
"barbarian"
,
"lvl"
: 4
}
}
},
{ insertOne :
{
"document"
:
{
"_id"
: 5,
"char"
:
"Taeln"
,
"class"
:
"fighter"
,
"lvl"
: 3
}
}
},
{ updateOne :
{
"filter"
: {
"char"
:
"Eldon"
},
"update"
: { $set : {
"status"
:
"Critical Injury"
} }
}
},
{ deleteOne :
{
"filter"
: {
"char"
:
"Brisbane"
} }
},
{ replaceOne :
{
"filter"
: {
"char"
:
"Meldane"
},
"replacement"
: {
"char"
:
"Tanys"
,
"class"
:
"oracle"
,
"lvl"
: 4 }
}
}
]
);
}
catch
(e) {
print(e);
}
|
操作结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"acknowledged"
:
true
,
"deletedCount"
: 1,
"insertedCount"
: 2,
"matchedCount"
: 2,
"upsertedCount"
: 0,
"insertedIds"
: {
"0"
: 4,
"1"
: 5
},
"upsertedIds"
: {
}
}
|
如果 第二个 insertOne 操作的 _id 是集合中已经存在的,则会抛出以下错误:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
BulkWriteError({
"writeErrors"
: [
{
"index"
: 0,
"code"
: 11000,
"errmsg"
:
"E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4 }"
,
"op"
: {
"_id"
: 5,
"char"
:
"Taeln"
}
}
],
"writeConcernErrors"
: [ ],
"nInserted"
: 1,
"nUpserted"
: 0,
"nMatched"
: 0,
"nModified"
: 0,
"nRemoved"
: 0,
"upserted"
: [ ]
})
|
默认情况下 ordered 为 true, 顺序执行时遇到错误就停止执行(后续的操作不会被执行)。
无序批量写
characters 集合包含以下文档:
1
2
3
|
{
"_id"
: 1,
"char"
:
"Brisbane"
,
"class"
:
"monk"
,
"lvl"
: 4 },
{
"_id"
: 2,
"char"
:
"Eldon"
,
"class"
:
"alchemist"
,
"lvl"
: 3 },
{
"_id"
: 3,
"char"
:
"Meldane"
,
"class"
:
"ranger"
,
"lvl"
: 3 }
|
bulkWrite() 在集合上执行批量操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
try
{
db.characters.bulkWrite(
[
{ insertOne :
{
"document"
:
{
"_id"
: 4,
"char"
:
"Dithras"
,
"class"
:
"barbarian"
,
"lvl"
: 4
}
}
},
{ insertOne :
{
"document"
:
{
"_id"
: 4,
"char"
:
"Taeln"
,
"class"
:
"fighter"
,
"lvl"
: 3
}
}
},
{ updateOne :
{
"filter"
: {
"char"
:
"Eldon"
},
"update"
: { $set : {
"status"
:
"Critical Injury"
} }
}
},
{ deleteOne :
{
"filter"
: {
"char"
:
"Brisbane"
} }
},
{ replaceOne :
{
"filter"
: {
"char"
:
"Meldane"
},
"replacement"
: {
"char"
:
"Tanys"
,
"class"
:
"oracle"
,
"lvl"
: 4 }
}
}
],
{ ordered :
false
}
);
}
catch
(e) {
print(e);
}
|
操作结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
BulkWriteError({
"writeErrors"
: [
{
"index"
: 0,
"code"
: 11000,
"errmsg"
:
"E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4 }"
,
"op"
: {
"_id"
: 4,
"char"
:
"Taeln"
}
}
],
"writeConcernErrors"
: [ ],
"nInserted"
: 1,
"nUpserted"
: 0,
"nMatched"
: 2,
"nModified"
: 2,
"nRemoved"
: 1,
"upserted"
: [ ]
})
|
无序操作,尽管操作过程中出现错误,剩余的操作也不会就此终止执行。
基于 Write Concern 的批量写
enemies 集合包含以下文档:
1
2
3
4
|
{
"_id"
: 1,
"char"
:
"goblin"
,
"rating"
: 1,
"encounter"
: 0.24 },
{
"_id"
: 2,
"char"
:
"hobgoblin"
,
"rating"
: 1.5,
"encounter"
: 0.30 },
{
"_id"
: 3,
"char"
:
"ogre"
,
"rating"
: 3,
"encounter"
: 0.2 },
{
"_id"
: 4,
"char"
:
"ogre berserker"
,
"rating"
: 3.5,
"encounter"
: 0.12}
|
以下使用 write concern 值为 "majority" 及 timeout 为 100 毫秒来执行批量写操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
try
{
db.enemies.bulkWrite(
[
{ updateMany :
{
"filter"
: {
"rating"
: { $gte : 3} },
"update"
: { $inc : {
"encounter"
: 0.1 } }
},
},
{ updateMany :
{
"filter"
: {
"rating"
: { $lt : 2} },
"update"
: { $inc : {
"encounter"
: -0.25 } }
},
},
{ deleteMany : {
"filter"
: {
"encounter"
{ $lt : 0 } } } },
{ insertOne :
{
"document"
:
{
"_id"
:5,
"char"
:
"ogrekin"
,
"rating"
: 2,
"encounter"
: 0.31
}
}
}
],
{ writeConcern : { w :
"majority"
, wtimeout : 100 } }
);
}
catch
(e) {
print(e);
}
|
如果副本集中所有必需节点确认写入操作所需的总时间大于wtimeout,则在wtimeout 时间过去时将显示以下writeConcernError。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
BulkWriteError({
"writeErrors"
: [ ],
"writeConcernErrors"
: [
{
"code"
: 64,
"errInfo"
: {
"wtimeout"
:
true
},
"errmsg"
:
"waiting for replication timed out"
}
],
"nInserted"
: 1,
"nUpserted"
: 0,
"nMatched"
: 4,
"nModified"
: 4,
"nRemoved"
: 1,
"upserted"
: [ ]
})
|
结果集显示执行的操作,因为writeConcernErrors错误不是任何写入操作失败的标志。
https://docs.mongodb.com/v3.4/reference/method/db.collection.bulkWrite