# MongoDB insert 小知識
分享在 MongoDB 常常容易忘記,但卻很重要的事項
1. 不會遇到 (db, colleciton) 不存在的問題
2. 遇到 **E11000 duplicate key error** 的處理方式
## 背景
有天一樣快樂地在練習 MongoDB 的過程中,因為太心急,產生了一些錯誤,這才去細看關於 insert command 的細節
在一個 collection 內正常新增一個名字為 amy 的資料
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.insert({"_id":1,"name":"amy"})
{ acknowledged: true, insertedIds: { '0': 1 } }
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.find({})
[ { _id: 1, name: 'amy' } ]
```
後面心急,敲錯指令,又再度打了一次新增
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.insert({"_id":1,"name":"amy"})
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: demo.dummy index: _id_ dup key: { _id: 1 }
Result: BulkWriteResult {
result: {
ok: 1,
writeErrors: [
WriteError {
err: {
index: 0,
code: 11000,
errmsg: 'E11000 duplicate key error collection: demo.dummy index: _id_ dup key: { _id: 1 }',
errInfo: undefined,
op: { _id: 1, name: 'amy' }
}
}
],
writeConcernErrors: [],
insertedIds: [ { index: 0, _id: 1 } ],
nInserted: 0,
nUpserted: 0,
nMatched: 0,
nModified: 0,
nRemoved: 0,
upserted: [],
opTime: { ts: Timestamp({ t: 1669558344, i: 8 }), t: Long("448") }
}
}
```
看到跳出 duplicate key error 的錯誤不意外,因為 _id:1 的紀錄剛才已經被新增到了 collection 中,所以基於 _id 要保持 unique 的原則,這次操作當然要失敗。
## 實驗
於是就開始在想,那如果是一次新增多筆記錄,然後其中有幾筆紀錄是 duplicate key 的話,那這次的操作結果會是如何?
實驗環境準備,先新增一筆紀錄(2)
```javascript!
db.dummy.insert({"_id":2,"name":"user2"})
```
接著一次新增三筆紀錄
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.insert([{"_id":1,"name":"user1"},{"_id":2,"name":"user2"},{"_id":3,"name":"user3"}])
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: demo.dummy index: _id_ dup key: { _id: 2 }
Result: BulkWriteResult {
result: {
ok: 1,
writeErrors: [
WriteError {
err: {
index: 1,
code: 11000,
errmsg: 'E11000 duplicate key error collection: demo.dummy index: _id_ dup key: { _id: 2 }',
errInfo: undefined,
op: { _id: 2, name: 'user2' }
}
}
],
writeConcernErrors: [],
insertedIds: [
{ index: 0, _id: 1 },
{ index: 1, _id: 2 },
{ index: 2, _id: 3 }
],
nInserted: 1,
nUpserted: 0,
nMatched: 0,
nModified: 0,
nRemoved: 0,
upserted: [],
opTime: { ts: Timestamp({ t: 1669560013, i: 5 }), t: Long("448") }
}
}
```
上述的錯誤中有一個亮點,**nInserted: 1**,雖然遇到了 duplicate key error,但只有一筆資料(_id:1)被成功新增了
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.find({})
[ { _id: 2, name: 'user2' }, { _id: 1, name: 'user1' } ]
```
這時心裡想的是我的 _id:3 紀錄也想要跳過這個錯誤,新增進去不行嗎?
```javascript
db.collection.insert(
<document or array of documents>,
{
writeConcern: <document>,
ordered: <boolean>
}
)
```
關於 ordered 的介紹
> Optional. If true, perform an ordered insert of the documents in the array, and if an error occurs with one of documents, MongoDB will return without processing the remaining documents in the array.
>
> If false, perform an unordered insert, and if an error occurs with one of documents, continue processing the remaining documents in the array.
>
> Defaults to true.
## 關閉 insert ordered
那就重新來過一次
先新增一筆紀錄(2)
```javascript!
db.dummy.insert({"_id":2,"name":"user2"})
```
接著一次新增三筆紀錄
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.insert([{"_id":1,"name":"user1"},{"_id":2,"name":"user2"},{"_id":3,"name":"user3"}],{ "ordered": false })
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: demo.dummy index: _id_ dup key: { _id: 2 }
Result: BulkWriteResult {
result: {
ok: 1,
writeErrors: [
WriteError {
err: {
index: 1,
code: 11000,
errmsg: 'E11000 duplicate key error collection: demo.dummy index: _id_ dup key: { _id: 2 }',
errInfo: undefined,
op: { _id: 2, name: 'user2' }
}
}
],
writeConcernErrors: [],
insertedIds: [
{ index: 0, _id: 1 },
{ index: 1, _id: 2 },
{ index: 2, _id: 3 }
],
nInserted: 2,
nUpserted: 0,
nMatched: 0,
nModified: 0,
nRemoved: 0,
upserted: [],
opTime: { ts: Timestamp({ t: 1669560222, i: 8 }), t: Long("448") }
}
}
```
雖然一樣跳出了 duplicate key error,但有個地方改變了,**nInserted: 2**,我們這次成功寫進去的資料有兩筆,不會因為遇到錯誤而停下來!
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummy.find({})
[
{ _id: 2, name: 'user2' },
{ _id: 1, name: 'user1' },
{ _id: 3, name: 'user3' }
]
```
## 要小心發生於MongoDB的typo
一般來說,我們都預期如果 insert 的 collection 不存在,應該會報某種 not exist 的 runtime exception。
目前可以看到在 demo(db) 底下只有一個 collection(dummy)。
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> show collections
dummy
```
如果這個時候我下了這樣的指令,那是會成功的,如果你在很緊張的情況下,本來就容易打錯字,可能會造成一些誤會,所以要特別注意 mongodb 對於不存在的 db, collection 新增資料的行為那是會順利執行下去的
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> db.dummyeee.insert({"_id":2,"name":"user2"})
{ acknowledged: true, insertedIds: { '0': 2 } }
```
那如果我選擇使用一個根本不存在的 db 呢?像是 **yeeeeee**,沒錯,它就直接切過去了!不會跳出錯誤停醒你說這個 db 根本不存在,所以一樣要小心緊急情況下可能的 typo
```shell
Atlas atlas-gu26kd-shard-0 [primary] demo> show dbs
demo 112.00 KiB
sample_airbnb 52.61 MiB
sample_analytics 9.13 MiB
sample_geospatial 1.36 MiB
sample_guides 40.00 KiB
sample_mflix 47.41 MiB
sample_restaurants 7.63 MiB
sample_supplies 1.12 MiB
sample_training 51.82 MiB
sample_weatherdata 3.85 MiB
admin 336.00 KiB
local 1.09 GiB
Atlas atlas-gu26kd-shard-0 [primary] demo> use yeeeeee
switched to db yeeeeee
Atlas atlas-gu26kd-shard-0 [primary] yeeeeee>
```