2014-07-17 27 views
3

我想更新一個涉及讀取其他集合和複雜修改的文檔,因此findAndModify()中的更新運算符不能滿足我的目的。用Mongoose在MongoDB中查找,修改和保存流程時發生衝突

這是我有:

Collection.findById(id, function (err, doc) { 

    // read from other collection, validation 
    // modify fields in doc according to user input 
    // (with decent amount of logic) 

    doc.save(function (err, doc) { 
     if (err) { 
     return res.json(500, { message: err }); 
     } 

     return res.json(200, doc); 
    }); 
} 

我擔心的是,這種流動可能導致衝突,如果多個客戶發生修改同一文檔。
據說here是:在一個單一的文件

操作總是原子性的MongoDB數據庫

我有點無所適從Operations的意思。

  • 這是否意味着,findById()將獲得鎖,直到doc超出範圍(響應發送後),所以不會有衝突? (我不這麼認爲)
  • 如果沒有,如何修改我的代碼以支持多個客戶端知道他們將修改Collection?
  • 如果發生Mongoose報告衝突,它會發生衝突嗎?
  • 如何處理可能的衝突?是否可以手動鎖定收藏夾?
    • 我看到的建議,使用貓鼬的versionKey(或時間戳)和重試陳舊文件
    • 不要完全使用MongoDB的...

感謝。


爲指針編輯

感謝@jibsales,我現在用的貓鼬的versionKey(時間戳也將工作),以避免犯衝突。

aaronheckmann — Mongoose v3 part 1 :: Versioning

參見此示例代碼:
https://gist.github.com/anonymous/9dc837b1ef2831c97fe8

+0

在註釋塊(附加邏輯)中是否有異步代碼?看起來你是這樣做的,在這種情況下,你最終可能會保存陳舊的數據。你可能會有這樣的成功:https://www.npmjs.org/package/mongoose-timestamp。 – dylants

+0

是的,我還發現一些建議使用Mongoose的versionKey並重試過時的文檔。這是你的建議嗎? – leesei

回答

3

操作指的是讀/寫。請記住,MongoDB不是符合ACID標準的數據層,如果您需要真正的ACID合規性,您最好選擇另一種技術。也就是說,您可以通過兩階段提交技術outlined in this article in the MongoDB docs實現原子性和隔離。這不是一件容易的事情,所以要準備一些繁重的工作,因爲你需要使用本地驅動程序而不是Mongoose。同樣,我的最終建議是不要喝NoSQL koolaid,如果你需要交易支持,它聽起來像你一樣。

+0

我看到一些建議使用Mongoose的versionKey並在研究後重試,你推薦這樣的解決方案嗎? – leesei

1

當MongoDB接收到更新文檔的請求時,它將鎖定數據庫直到它完成操作。 MongoDB收到的任何其他請求將一直等到鎖定操作完成並且數據庫解鎖。這種鎖定/等待行爲是自動的,所以沒有任何衝突需要處理。您可以在FAQ的Concurrency部分找到關於此行爲的更多信息。

請參閱jibsales的答案,瞭解MongoDB推薦的用於執行多文檔事務的技術的鏈接。

有幾個NoSQL數據庫可以完成完整的ACID事務,這會讓您的生活變得更加輕鬆。 FoundationDB就是這樣一個數據庫。數據存儲爲鍵值,但它通過層支持多個數據模型。

完全披露:我是FoundationDB的工程師。