2015-08-09 30 views
0

說我開發後端的輪詢應用程序。用戶在輪詢中選擇一個選項,並請求更新輪詢文檔和用戶文檔。不同型號更新兩個文件中的一個請求

// Express endpoint for /vote/:pollId/:optionIndex 
// (middleware puts users document on req.user) 
function(req, res) { 

    //Check if the user has already voted on this poll 
    ... 

    Polley.findByIdAndUpdate(req.params.pollId, { 
     //increment the number of votes on the selected options by one 
     $inc: ... 
    }, { 
     new: true 
    }, function (err, data) { 
     //If err send error message 
     ... 

     // Now update the users document, so that the user 
     // can't vote on this poll again and so the user can go 
     // back and see what he/she voted for. 
     User.findByIdAndUpdate(req.user._id, 
      { 
       $push: { 
        votes: { 
         polleyId: req.params.polleyId, 
         optionIndex: req.params.optionIndex 
        } 
       } 
      }, 
      function (err, user) { 
       // HERE IS THE PROBLEM. 
       // what if error happens here? Then the user will be able 
       // to vote on this poll one more time since the vote was not 
       // successfully saved in the users document. 
      } 
     ); 

     res.status(200).json({ poll_votes: data.votes, message: "Vote Successful." }); 
    }); 
} 

我刪除了部分與...因爲執行不相關的問題。

這些操作都需要在一個呼叫進行,這樣用戶不必只更新調查文檔,但不是用戶文件的權力。

的問題,我在代碼中的註釋指出的是,如果我第一次更新調查文件,之後更新用戶文檔,第一操作可能是成功的,而第二次是沒有的。

如何確保兩個操作要麼失敗或成功?

回答

1

的MongoDB不支持不同的收藏和交易的原子更新。要回答你的問題,我看到兩種方法:

  1. 模擬交易對不同的集合使用Two Phase Commits
  2. 遷移您的數據結構來patching way,讓你做原子操作(如谷歌文檔一樣)。
  3. 我可以建議使用TokuMX(它支持事務),而不是MongoDB,但在問題的標籤你指出nodejs其中使用Tokumx爲此目的不可能因交易與線程相關聯。

如果您需要支持事務並需要使用MongoDB,我會建議您嘗試Two Phase Commits,因爲這是解決您的任務的最簡單方法。

+0

感謝@ArtemBaranovskii,兩所階段提交就是我一直在尋找,並聽取需要!即使我對這個答案感到滿意,你能否引用一些文章來解釋「修補方式」,因爲我不熟悉它? – micnil

+0

那麼,'修補方式'是指JSON修補程序規範https://tools.ietf.org/html/rfc6902常見的想法是將您的本質存儲爲差異序列。所以你可以做任何困難的原子操作。但它不適用於所有應用程序。我只是提供了它作爲可能的解決方案,因爲我有同樣的問題和JSON補丁適合我。 –

相關問題