Skip to content

Commit fa4d6eb

Browse files
committed
fix(document): avoid double calling validators on paths in document arrays underneath subdocuments
Fix #15335
1 parent 5325a85 commit fa4d6eb

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

lib/document.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2726,7 +2726,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
27262726
const modifiedPaths = doc.modifiedPaths();
27272727
for (const subdoc of subdocs) {
27282728
if (subdoc.$basePath) {
2729-
const fullPathToSubdoc = subdoc.$isSingleNested ? subdoc.$__pathRelativeToParent() : subdoc.$__fullPathWithIndexes();
2729+
const fullPathToSubdoc = subdoc.$__pathRelativeToParent();
27302730

27312731
// Remove child paths for now, because we'll be validating the whole
27322732
// subdoc.
@@ -2736,11 +2736,12 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
27362736
paths.delete(fullPathToSubdoc + '.' + modifiedPath);
27372737
}
27382738

2739+
const subdocParent = subdoc.$parent();
27392740
if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
27402741
// Avoid using isDirectModified() here because that does additional checks on whether the parent path
27412742
// is direct modified, which can cause performance issues re: gh-14897
2742-
!doc.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2743-
!doc.$isDefault(fullPathToSubdoc)) {
2743+
!subdocParent.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2744+
!subdocParent.$isDefault(fullPathToSubdoc)) {
27442745
paths.add(fullPathToSubdoc);
27452746

27462747
if (doc.$__.pathsToScopes == null) {

test/document.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14455,6 +14455,53 @@ describe('document', function() {
1445514455
assert.strictEqual(car.vin, undefined);
1445614456
assert.strictEqual(car.sunroof, true);
1445714457
});
14458+
14459+
it('avoids double validating document arrays underneath single nested (gh-15335)', async function() {
14460+
let arraySubdocValidateCalls = 0;
14461+
let strValidateCalls = 0;
14462+
14463+
const embeddedSchema = new mongoose.Schema({
14464+
arrObj: {
14465+
type: [{
14466+
name: {
14467+
type: String,
14468+
validate: {
14469+
validator: () => {
14470+
++arraySubdocValidateCalls;
14471+
return true;
14472+
}
14473+
}
14474+
}
14475+
}]
14476+
},
14477+
arrStr: {
14478+
type: [{
14479+
type: String,
14480+
validate: {
14481+
validator: () => {
14482+
++strValidateCalls;
14483+
return true;
14484+
}
14485+
}
14486+
}]
14487+
}
14488+
});
14489+
14490+
const TestModel = db.model('Test', new Schema({ child: embeddedSchema }));
14491+
await TestModel.create({
14492+
child: {
14493+
arrObj: [
14494+
{
14495+
name: 'arrObj'
14496+
}
14497+
],
14498+
arrStr: ['arrStr']
14499+
}
14500+
});
14501+
assert.strictEqual(arraySubdocValidateCalls, 1);
14502+
assert.strictEqual(strValidateCalls, 1);
14503+
14504+
});
1445814505
});
1445914506

1446014507
describe('Check if instance function that is supplied in schema option is available', function() {

0 commit comments

Comments
 (0)