This is My Model Schema:
````
const BalanceSchema = new Schema({
name: { type: String, required: true },
rate: { type: Number, required: true },
amount: { type: Number, required: true },
});
const InvoiceSchema = new Schema({
key: { type: String, required: true, match: /(EST|INV|BIL)-w+/ },
name: { type: String, required: true },
taxes: [BalanceSchema]
});
And This How I Update my documents:
Invoice.findOneAndUpdate({
_id: request.params.invoiceId,
}, { status: request.body }, { new: true, runValidators: true }).exec(function (error, invoice) {
if (error) response.apiError(error);
if (!invoice) return response.apiNotFound();
return response.apiResponse(invoice);
});
````
The problem is when I execute this function (findOnAndUpdate), the option runValidators: true doesn't work on taxes subDocuments but only on invoice fields??!!!
how do you know the validators aren't running? Those fields are required on each subdocument within the taxes
array but i don't know what the object looks like before the updte. Those fields might already exist?
Your repro script is also not in async with your schema: there's no status
field on the InvoiceSchema
, so I can't tell what you're trying to do here.
This example works for me (it logs out 'running validator'):
const mongoose = require('mongoose');
const co = require('co');
mongoose.Promise = global.Promise;
const GITHUB_ISSUE = `gh-5234`;
exec()
.then(() => {
console.log('successfully ran program');
process.exit(0);
})
.catch(error => {
console.error(`Error: ${ error }\n${ error.stack }`);
});
function exec() {
return co(function*() {
const db = mongoose.createConnection(`mongodb://localhost:27017/${ GITHUB_ISSUE }`)
const childSchema = {
age: { type: Number, required: function() {
console.log('running validator');
return true;
} }
};
const schema = new mongoose.Schema({
name: String,
children: [childSchema]
});
const Model = db.model('Model', schema);
yield Model.remove({});
const doc = yield Model.create({ name: 'test', children: [
{ age: 4 }
]});
const update = yield Model.findOneAndUpdate(
{ _id: doc._id },
{ name: 'new name' },
{ new: true, runValidators: true }
);
console.log(update.children);
});
}
the log output:
running validator
[ { _id: 59154598fc30edb271a5f10f, age: 4 } ]
successfully ran program
This is my what my request.body looks like:
````
{
"type": "bill",
"name": "TEST",
"key": "BIL-542354",
"date": "2017-05-26",
"taxes": [{
"name": "TVA"
}],
// other datas ....
}
````
I should have an error because rate and amount in balance schema are not mentioned in my body json, but Instead the document is updated....
@medkhelifi I'm still confused. Why are you updating with { status: request.body }
. That field doesn't exist in your schema
@varunjayaraman I'm sorry it's my fault, I copied the wrong snipped;
This is my findOneAndUpdate function:
Invoice.findOneAndUpdate({
_id: request.params.invoiceId,
createdBy: request.user.id
}, request.body, { new: true, runValidators: true }).exec(function (error, invoice) {
if (error) return response.apiError(error);
if (!invoice) return response.apiNotFound();
return response.apiResponse(invoice);
});
And this is what my request.body looks like:
{
"type": "bill",
"name": "TEST",
"key": "BIL-542354",
"date": "2017-05-26",
"taxes": [{
"name": "TVA"
// you can see other required taxes (BalanceSchema) fields are missing, I only mentionned "name"
}],
// other datas ....
}
As I told you I should have an error because rate and amount in taxes (BalanceSchema) are not mentioned in my body json, but Instead the document is updated....
PS: The validation work fine on taxes whene I use .save() Instead of findOneAndUpdate()
ok so there are 3 problems here:
1) mongoose won't deep diff inside the array you're updating, it's just going to overwrite it. YOu need to be careful how you do updates to array subdocs. Instead if you know youre going to be updating an array, you should do something like:
{ 'taxes.0.name': someValue }
2) mongoose validators will only run in a findByIdAndUpdate
operation with runValidators
set to true on the fields you are trying to update:
3) as you can see from that photo from mongoose docs, required
validators will ONLY run on $unset
operations
Thank you for your response:
mongoose validators will only run in a findByIdAndUpdate operation with runValidators set to true on the fields you are trying to update
Can we see mongoose validators running in findOneAndUpdate in futur 茅volutions???
I will add it as a new feature request. I remember talking to @vkarpov15 about this and I think the plan is to make validators run by default in 5.x. However, it wont be possible to run validators for the entire object because mongoose can only see what you're updating in a findByIdAndUpdate
call. IF you want to validate an update operation based on the entire document, you'll need to do a .save()
Most helpful comment
Thank you for your response:
Can we see mongoose validators running in findOneAndUpdate in futur 茅volutions???