【问题标题】:Solve a transaction with mongodb (waterline.js) and node.js (sails.js)使用 mongodb (waterline.js) 和 node.js (sails.js) 解决事务
【发布时间】:2017-04-27 19:49:13
【问题描述】:

鉴于这种情况:

-UserA 发布了一个Campaign,上传了给定数量的照片。

-其他用户可以上传照片

-UserA可以接受上传的照片

-照片的所有者为每张接受的照片获得 1 个硬币

-对于每张接受的照片,活动中可能的照片数量都会减少。

我解决了这样的“接受照片”功能(伪代码):

accept: function (req, res, next) {

        var photos = req.param('photos'); // [1, 2, 5]
        var campaign_id = req.param('campaign_id'); //1

        Photo.update(photos, {status:'accepted'}).exec(function afterwards(err, updatedPhotos) 
            {
                     //get the users Ids from the updatedPhotos
                      // also know how many photos of each user were accepted

                      User.update(users){
                         //increase the amount of coins of this user 
                       }

                      Campaign.update(amountOfAcceptedPhotos){
                         //decrease the amount of selectable photos. 
                       }

            })

}

首先一切都很顺利,直到我注意到当您使用相同的 photoID 快速发送相同的请求时,用户将获得同一张照片的多个硬币!我怎样才能防止这种情况?

如果您想查看确切的功能,这是整个代码的链接: https://jsfiddle.net/zsmuoh0x/

【问题讨论】:

    标签: javascript node.js mongodb transactions sails.js


    【解决方案1】:

    我编写了一个库来实现docs 中描述的两阶段提交系统。在这种情况下它可能会有所帮助。 Fawn - Transactions for MongoDB。示例:将 20 美元从一个银行账户转入另一个银行账户

    var Fawn = require("Fawn");
    
    // intitialize Fawn
    Fawn.init("mongodb://127.0.0.1:27017/testDB");
    
    /**
    optionally, you could initialize Fawn with mongoose
    
    var mongoose = require("mongoose");
    mongoose.connect("mongodb://127.0.0.1:27017/testDB");
    Fawn.init(mongoose);
    **/
    
    // after initialization, create a task
    var task = Fawn.Task();
    
    // assuming "Accounts" is the Accounts collection
    task.update("Accounts", {_id: "Sender"}, {$inc: {balance: -20}})
      .update("Accounts", {_id: "Reciever"}, {$inc: {balance: 20}})
      .run()
      .then(function(results){
        // task is complete 
    
        // result from first operation
        var firstUpdateResult = results[0];
    
        // result from second operation
        var secondUpdateResult = results[1];
      })
      .catch(function(err){
        // Everything has been rolled back.
    
        // log the error which caused the failure
        console.log(err);
      });
    

    【讨论】:

    • 可能包含链接中的一些细节,以便未来的用户可以找到信息——即使链接失效。
    【解决方案2】:

    在您的特定情况下,我猜您将用户选择的照片存储在活动集合中的某个位置,例如:

    {Id:999, Name: mycampaign, photos:[1,7] }
    

    因此,更新查询应该按 id 和按照片 id 选择文档。如果要添加图片3:

    db.campaigns.update({id:999, photos:3},. {$addToSet:{photos:3}})
    

    如果结果是更新了 1 个文档,则增加用户硬币。

    PS:我是手机接听

    【讨论】:

      猜你喜欢
      • 2017-02-11
      • 1970-01-01
      • 2017-11-26
      • 2017-08-01
      • 2011-10-01
      • 1970-01-01
      • 2013-07-21
      相关资源
      最近更新 更多