Skip to content

Instantly share code, notes, and snippets.

Last active April 2, 2018 21:12
Show Gist options
  • Save mpalmerlee/9709085 to your computer and use it in GitHub Desktop.
Save mpalmerlee/9709085 to your computer and use it in GitHub Desktop.
Save MongoDB Document With Concurrent Edit Protection
var mongoose = require("mongoose");
var ObjectId = mongoose.Schema.Types.ObjectId;
//create schema for a post
var PostSchema = new mongoose.Schema({
nonce: ObjectId, //this is used for protecting against concurrent edits:
name: String,
dateCreated: { type: Date, default: },
dateLastChanged: { type: Date, default: },
postData: mongoose.Schema.Types.Mixed
//compile schema to model
exports.PostModel = db.model('post', PostSchema);
var postService = require('./postService');
exports.AppendPostText = function(postId, text, callback){
saveGameByIdWithConcurrencyProtection(postId, function(doc, cb){
doc.postData.text += text;
cb(null, data);
}, 0, function(err, doc){
callback(err, doc);
var mongoose = require("mongoose");
var models = require("./documentModel");
This method uses the nonce field in the document to protect against concurrent edits on the post document
transformFunction will be given the post doc and should callback the data to update:
transformFunction(doc, callback)
var savePostByIdWithConcurrencyProtection = function(postId, transformFunction, retries, callback){
FindPostById(postId, function(err, doc){
if(err || !doc){
callback(err || "Unable to find post in savePostByIdWithConcurrencyProtection");
transformFunction(doc, function(err, data){
data.nonce = new mongoose.Types.ObjectId;
//setTimeout(function(){ //setTimeout for testing concurrent edits
models.PostModel.update({"_id":postId, "nonce":doc.nonce}, data, function(err, numberAffected, raw){
//console.log("savePostByIdWithConcurrencyProtection: ", numberAffected, raw);
if(!numberAffected && retries < 10){
//we weren't able to update the doc because someone else modified it first, retry
console.log("Unable to savePostByIdWithConcurrencyProtection, retrying ", retries);
//retry with a little delay
savePostByIdWithConcurrencyProtection(postId, transformFunction, (retries + 1), callback);
}, 20);
} else if(retries >= 10){
//there is probably something wrong, just return an error
callback("Couldn't update document after 10 retries in savePostByIdWithConcurrencyProtection");
} else {
FindPostById(postId, callback);
//}, 5000);
var FindPostById = function(id, callback){
//search for an existing post
models.PostModel.findOne({"_id":id}, function(err, doc){
console.error("FindPostById:", err);
} else if(!doc){
var msg = "Could Not FindPostById:" + id;
return callback(msg);
callback(err, doc);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment