代码之家  ›  专栏  ›  技术社区  ›  user2932053

NodeJS、ExpressJS、Mongoose 4.4、Nonce用于并发和Document.update

  •  0
  • user2932053  · 技术社区  · 8 年前

    我有以下组合:NodeJS、Express、MongoDB和Mongoose。我用mongoose promises实现了一个nonce,允许并发编辑。请参见以下内容:

    //schema
    var item_schema = {
        //_id: {type: Schema.ObjectId, required: true},
        name: {type: String, required: true, index: { unique: true }},
        code: {type: String, required: true, index: { unique: true }},
        date_time_created: {type: Date, required: true},
        date_time_updated: {type: Date, required: true},
        nonce: {type: Schema.ObjectId}
    };
    
    //model
    var item_model = mongoose.model('item', schema);
    
    //update
    var concurrency_update = function(req, res, retries) {
    
        var promise = model.findById(req.params.id).exec();
    
        var updated_nonce = mongoose.Types.ObjectId();
    
        promise.then(function(document){ //find document response
    
            if(!document) {
                res.status = 404;
                return Promise.reject( { "message" : req.params.id + ' document does not exist' } );
            }
            var now = new Date();
            if(req.body.code) {
                document.code = req.body.code;
                document.date_time_updated = now;
            }
            if(req.body.name) {
                document.name = req.body.name;
                document.date_time_updated = now;
            }
            if(!document.nonce) {
                document.nonce = updated_nonce;
                var old_nonce = document.nonce;
            }
            else {
                var old_nonce = document.nonce;
                document.nonce = updated_nonce;
            }
            return document.update({ "_id" : req.params.id, "nonce" : old_nonce }).exec();
    
        }).then(function(raw){ //update response
    
            var number_affected = raw.n;
            console.log(raw);
            if(!number_affected && retries < 10){
                //we weren't able to update the doc because someone else modified it first, retry
                console.log("Unable to update, retrying ", retries);
                //retry with a little delay
                setTimeout(function(){
                    concurrency_update(req, res, (retries + 1));
                }, 20);
            } else if (retries >= 10){
                //there is probably something wrong, just return an error
                return Promise.reject({ "message" : "Couldn't update document after 10 retries in update"});
            } else {
                res.json({"message": req.params.id + ' document was update'});
            }
    
        }).catch(function(err){
            res.send(err.message);
        });
    

    并发更新基于以下内容: http://www.mattpalmerlee.com/2014/03/22/a-pattern-for-handling-concurrent/

    阅读猫鼬文档,更新就是基于此。 http://mongoosejs.com/docs/api.html#document_Document-update

    然而,当代码进入final.then(//更新响应)时,我看到了原始的。n(numberAffected)=1但数据库从未更新?

    答案可能很接近,但我错过了。 我错过了什么?

    1 回复  |  直到 8 年前
        1
  •  0
  •   user2932053 user2932053    8 年前

    在@blakes_seven的评论之后,我能够删除nonce的使用,并使用原子修饰符应用更新。这是更新的测试代码。

    //schema
    var item_schema = {
        //_id: {type: Schema.ObjectId, required: true},
        name: {type: String, required: true, index: { unique: true }},
        code: {type: String, required: true, index: { unique: true }},
        date_time_created: {type: Date, required: true},
        date_time_updated: {type: Date, required: true},
        nonce: {type: Schema.ObjectId}
    };
    
    //model
    var item_model = mongoose.model('item', schema);
    
    //update
    var concurrency_update = function(req, res, retries) {
    
        var updated_data = {};
        if(req.body.code) {
            updated_data.code = req.body.code;
        }
        if(req.body.name) {
            updated_data.name = req.body.name;
        }
        if(!req.body.name.nonce) {
            updated_data.nonce = mongoose.Types.ObjectId();
        }
    
        if(updated_data !== {}) {
            var update = {
                $currentDate: {
                    date_time_updated: true
                },
                $set: updated_data
            };
            var promise = model.update({"_id": req.params.id}, update).exec();
    
            promise.then(function (raw) {
    
                var number_affected = raw.nModified;
                console.log(raw);
                if (!number_affected && retries < 10) {
                    //we weren't able to update the doc because someone else modified it first, retry
                    console.log("Unable to update, retrying ", retries);
                    //retry with a little delay
                    setTimeout(function () {
                        concurrency_update(req, res, (retries + 1));
                    }, 20);
                } else if (retries >= 10) {
                    //there is probably something wrong, just return an error
                    return Promise.reject({"message": "Couldn't update document after 10 retries in update"});
                } else {
                    res.json({"message": req.params.id + ' document was update'});
                }
    
            }).catch(function (err) {
                res.send(err.message);
            });
        }
        else {
            res.status = 400;
            res.send({"message": 'There is nothing specified in the payload to update!'})
        }
    };