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?
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 });
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)
?I'm using mongoose v4.5.8.