Skip to content

Commit 8ba97c3

Browse files
committed
fix: ensure update validators only call validators underneath single nested paths once
Fix #15436
1 parent d7d56dd commit 8ba97c3

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

lib/helpers/updateValidators.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ module.exports = function(query, schema, castedDoc, options, callback) {
147147
return callback(null);
148148
}
149149
}
150+
if (schemaPath.$isSingleNested) {
151+
alreadyValidated.push(updates[i]);
152+
}
150153

151154
schemaPath.doValidate(v, function(err) {
152155
if (schemaPath.schema != null &&
@@ -246,4 +249,3 @@ module.exports = function(query, schema, castedDoc, options, callback) {
246249
};
247250
}
248251
};
249-

test/model.updateOne.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,52 @@ describe('model: updateOne: ', function() {
31433143
assert.equal(r2.testArray[0].key, 'Type2');
31443144
assert.equal(r2.testArray[0].field2, field2update);
31453145
});
3146+
3147+
it('only calls validators under single nested subdocs once (gh-15436)', async function() {
3148+
let validateDetailsCalls = 0;
3149+
let validateNameCalls = 0;
3150+
3151+
const kittySchema = new mongoose.Schema({
3152+
informations: {
3153+
type: {
3154+
details: {
3155+
validate: function() {
3156+
validateDetailsCalls++;
3157+
return true;
3158+
},
3159+
type: {
3160+
name: {
3161+
type: String,
3162+
validate: function() {
3163+
validateNameCalls++;
3164+
return true;
3165+
}
3166+
}
3167+
}
3168+
}
3169+
}
3170+
}
3171+
});
3172+
3173+
const Kitten = db.model('Test', kittySchema);
3174+
3175+
// Update the document with validation enabled
3176+
await Kitten.updateOne(
3177+
{ _id: new mongoose.Types.ObjectId() },
3178+
{
3179+
informations: {
3180+
details: {
3181+
name: 'Zohra'
3182+
}
3183+
}
3184+
},
3185+
{ runValidators: true }
3186+
);
3187+
3188+
// Assert that each validator was only called once
3189+
assert.equal(validateDetailsCalls, 1);
3190+
assert.equal(validateNameCalls, 1);
3191+
});
31463192
});
31473193

31483194
async function delay(ms) {

0 commit comments

Comments
 (0)