批量插入數據,主鍵沖突報錯,並繼續執行后面操作
ordered : <boolean> --false
定義
db.collection.bulkWrite()
提供可控執行順序的批量寫操作。
語法格式如下:
1
2
3
4
5
6
7
|
db.collection.bulkWrite(
[ <operation 1>, <operation 2>, ... ],
{
writeConcern : <document>,
ordered : <boolean>
}
)
|
參數 | 類型 | 描述 |
---|---|---|
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。禁用writeConcern寫法{writeConcern:{w:-1}}
-
每一個寫操作數。
-
成功 inserted 或 upserted文檔的 _id 的組數。
db.test.bulkWrite([{insertOne:{"document":{"name":"xiaoxu","age":10}},{insertOne:{"document":{"name":"xiaoxu","age":10}},{insertOne:{"document":{"name":"xiaoliu","age":20}},{writeConcern:{w:-1},ordered:false}}])
這樣則可以忽略主鍵沖突,寫入兩條數據。
行為
bulkWrite() 接收一個寫操作的數組然后執行它們中的每一個。默認是有序的執行。
寫操作
insertOne
插入單個文檔到集合中。
1
2
3
|
db.collection.bulkWrite( [
{ insertOne : {
"document"
: <document> } }
] )
|
updateOne 及 updateMany
updateOne 更新集合中 filter 匹配的單個文檔。如果匹配到多個文檔 updateOne 僅更新第一個匹配到的文檔。
1
2
3
4
5
6
7
8
9
|
db.collection.bulkWrite( [
{ updateOne :
{
"filter"
: <document>,
"update"
: <document>,
"upsert"
: <boolean>
}
}
] )
|
updateMany 更新集合中所有匹配到的文檔。
1
2
3
4
5
6
7
8
9
|
db.collection.bulkWrite( [
{ updateMany :
{
"filter"
: <document>,
"update"
: <document>,
"upsert"
: <boolean>
}
}
] )
|
對字段的更新操作例如 $set 、$unset 、$rename等。
默認情況 upsert 為 false。
replaceOne
replaceOne 替換集合中 filter 匹配到的單個文檔。如果匹配到多個文檔 replaceOne 只會替換一個匹配到的文檔。
1
2
3
4
5
6
7
8
9
|
db.collection.bulkWrite([
{ replaceOne :
{
"filter"
: <document>,
"replacement"
: <document>,
"upsert"
: <boolean>
}
}
] )
|
replacement 字段中不能包含 update 操作。
默認情況 upsert 為 false。
deleteOne 及 deleteMany
deleteOne 刪除集合中 filter 匹配到的單個文檔。如果匹配到多個文檔 deleteOne 只會刪除一個匹配到的文檔。
1
2
3
|
db.collection.bulkWrite([
{ deleteOne : {
"filter"
: <document> } }
] )
|
deleteMany 刪除集合中 filter 匹配到的所有文檔。
1
2
3
|
db.collection.bulkWrite([
{ deleteMany : {
"filter"
: <document> } }
] )
|
_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 : <document> },
{ updateOne : <document> },
{ updateMany : <document> },
{ replaceOne : <document> },
{ deleteOne : <document> },
{ deleteMany : <document> }
]
)
|
默認情況下 ordered : true ,每個操作將會有序的執行,從第一個insertOne 到最后一個deleteMany 順序執行。
應用程序不依賴操作執行順序是,可以設置 ordered 為 false ,此時mongod 會重新排序操作來提高性能。
含有6個操作無序的 bulkWrite() 代碼如下:
1
2
3
4
5
6
7
8
9
10
11
|
db.collection.bulkWrite(
[
{ insertOne : <document> },
{ updateOne : <document> },
{ updateMany : <document> },
{ replaceOne : <document> },
{ deleteOne : <document> },
{ deleteMany : <document> }
],
{ 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