--- tags: Blue 的學習紀錄 --- # MongoDB - Mongoose Version Error 的成因 錯誤訊息: `VersionError: No matching document found for id "xxxxxxxxxxxxxxx"` ## _v 透過 Mongoose 存取 MongoDB 時,若觀察儲存在資料庫裡的欄位,會發現自動帶有 `_v` 這個欄位 這個欄位的名字叫做 Version Key Mongoose 官方文件介紹:https://mongoosejs.com/docs/guide.html#versionKey 這個 key 的作用是讓 Mongoose 對資料做版本控制,每當成功執行 `save()` 時,`_v` 就會 +1 以下直接以範例來說明,Version Key 如何做簡單的版本控制 :::info 這邊指的"版本控制",並不是像 git 這種強大的版本控制工具 而只是一種簡單的,能夠對一筆資料的版本做判斷而已 ::: ## 觸發錯誤的範例 ```sequence participant MongoDB participant Client # 資料庫 Note left of MongoDB: 一筆已存在 DB 裡的資料,_v = 0 # 開始讀取 MongoDB -> Client: Client A 讀取資料 Note right of Client: Client A 取得的 _v = 0 MongoDB -> Client: Client B 讀取資料 Note right of Client: Client B 取得的 _v = 0 # 開始寫入 Client -> MongoDB: Client B 寫入資料(傳入的 _v = 0) Note left of MongoDB: DB 裡的 _v 值等於傳入 _v 值,寫入成功,_v += 1 Note left of MongoDB: _v = 1 Client -> MongoDB: Client A 寫入資料(傳入的 _v = 0) Note left of MongoDB: DB 裡的 _v 值不等於傳入 _v 值,寫入失敗 Note left of MongoDB: 發生 Version Error! ``` 假設原來的資料是 `{ a:0, b:0 }` Client B 寫入的是 `{ a:0, b:1 }` Client A 寫入的是 `{ a:1, b:0 }` 若沒有 Version Key,就可能發生 Client B 所做的改變被 Client A 無意間給覆蓋掉 原本期待的最終結果是 `{ a:1, b:1 }`,結果卻只有 Client A 的輸入 `{ a:1, b:0 }` 有被寫入 :::warning 根據 Mongoose 文件的說明,只有 `save()` 才會檢查 Version Key ::: ## 直接 `update()`? 使用 Mongoose 做 `updateOne()` or `updateMany()` 的話,就不會檢查 Version Key,直接進行寫入,不會發生 Version Error 而且 `update()` 的執行效率也比較好,因為少了存取,直接就進行寫入 但對於覆蓋他筆寫入的風險,就得自行掌控 ## 用 `save()` 的話,如何避免 Version Error? 以我目前所知: - catch version error 在程式碼去 catch 這種 error,自動 retry - 在存取資料前,對資料加上 Lock,防止同時有其他人做改動 怎麼加 Lock 我不熟悉,只是知道可以這樣做而已 ## 後記 其實這只是[樂觀鎖](https://hackmd.io/@vegetableBird/SkOxBHJw9)將資料鎖住了的情況,並不是什麼錯誤
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up