Mongoose: Skip or Disable validation for mongoose model save() or create() call

Created on 30 Nov 2014  路  13Comments  路  Source: Automattic/mongoose

I'm looking for creating a new Document that is saved to the mongodb regardless of valid. I just want to temporarily skip or disable mongoose validation upon model save call.

In my case of CSV import, some required fields are not included in the CSV file, especially the reference fields to the other document. Then, the mongoose validation required check is not passed for the following example:

var product = mongoose.model("Product", Schema({
    name: {
        type: String,
        required: true
    },
    price: {
        type: Number,
        required: true,
        default: 0
    },
    supplier: {
        type: Schema.Types.ObjectId,
        ref: "Supplier",
        required: true,
        default: {}
    }
}));

var data = {
    name: 'Test',
    price: 99
}; // this may be array of documents either

product(data).save(function(err) {
  if (err) throw err;
});

Is it possible to let Mongoose know to not execute validation in the save() or create() call?

help

Most helpful comment

@vkarpov15, I'm struggling with the same issue as @golkir. I was looking at the test you linked (reproduced below) and it seems wrong to me. Shouldn't the assertion be something like assert.strictlyEqual(undefined, error) ?

doc.save({ validateBeforeSave: false }, function(error) {
  assert.ifError(error);
  db.close(done);
});

I'm using mongoose v4.5.8.

All 13 comments

Mongoose version is 3.8.19

Not at the moment, but you can bypass all validation and just use Model.collection.insert(), which defers to the mongodb driver.

With the Model.collection.insert function the middlewares (save, remove, etc) are not executed.
A workaround is to define a new function in your schema like this one:

schema.method('saveWithoutValidation', function(next) {
  var defaultValidate = this.validate;
  this.validate = function(next) {next();};

  var self = this;
  this.save(function(err, doc, numberAffected) {
    self.validate = defaultValidate;
    next(err, doc, numberAffected);
  });
});

Is there another alternative to achieve this behavior?

Not at the moment. 4.0 does have hooks for things like update(), etc. that you can use, but right now there's no good way to disable validation but still run save hooks. I'm open to a discussion about the best way to expose this functionality though, just in a separate issue.

@assisrafael thanks for the workaround, though it appears to be unsafe because intervening calls to save may not validate. In my usage I've made one small change: I set the validate function back to defaultValidate right after the save call rather than within the callback. I imagine this also might not work in all scenarios, as there may be asynchronous save hooks that are invoked prior to validate.

@khaled there's a validateBeforeSave option on schemas, see docs. I had forgotten about it when I made the Feb 23 comment, but if you set that option to false then save() will not run validate()

@vkarpov15 Thanks! The example seems to make it so that validation is turned off by default for all saves. It'd be nice to be able to pass an option to save - e.g. save(validate: false, ...), a la ActiveRecord.

thanks for the workaround @assisrafael

Hi, please help understand how validateBeforeSave in Model.prototype.save should be used. According to documentation, it should be Boolean within options object provided as the first argument to the save function. So, i do it like this: user.save({validateBeforeSave:false}, function(err,user) {...}.
However, validators still run and I've got validation errors. My mongoose version is 4.3.4 Any suggestsions?

@golkir can you provide a code sample? We have tests in place for that and seems to work fine...

@vkarpov15, I'm struggling with the same issue as @golkir. I was looking at the test you linked (reproduced below) and it seems wrong to me. Shouldn't the assertion be something like assert.strictlyEqual(undefined, error) ?

doc.save({ validateBeforeSave: false }, function(error) {
  assert.ifError(error);
  db.close(done);
});

I'm using mongoose v4.5.8.

No because error will be null not undefined. Either way, assert.ifError throws if the argument is truthy https://nodejs.org/api/assert.html#assert_assert_iferror_value

I think finally you should do like this:
Model.create(doc, { validateBeforeSave: false });

Was this page helpful?
0 / 5 - 0 ratings