2016-02-26 12 views
0

У меня есть следующая комбинация: NodeJS, Express, MongoDB и Mongoose. Я внедрил nonce с обещаниями mongoose, чтобы разрешить параллельные изменения. См .: следующийNodeJS, ExpressJS, Mongoose 4.4, Nonce для параллелизма и Document.update

//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

Однако, когда код входит в окончательный .then (// update response), я вижу raw.n (numberAffected) = 1, но база данных никогда не обновляется?

Ответы, вероятно, близки, но мне не хватает. Что мне не хватает на этом?

+1

Независимо от того, что вы делаете, у вас возникнут проблемы, если вы сначала извлечете из базы данных, используя вариант .findOne() 'любого типа. Вместо этого используйте ['.update()'] (http://mongoosejs.com/docs/api.html#model_Model.update) или ['.findOneAndUpdate()') (http://mongoosejs.com/docs/ api.html # model_Model.findOneAndUpdate) вместе с [модификаторами атомного обновления] (https://docs.mongodb.org/manual/reference/operator/update-field/). Они предназначены для изменения «на месте» и в текущем состоянии и не беспокоятся о том, что может произойти между извлечением и повторным сохранением данных. Измените свой шаблон. –

+0

@blake_seven - Итак, если я понимаю ваш комментарий, nonce действительно не нужен, если вы используете модификаторы атомного обновления, такие как $ set и $ remove. Я попробую это и опубликую решение, если оно будет найдено. – thxmike

ответ

0

После комментария @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!'}) 
    } 
};