Skip to content

Commit 5851261

Browse files
committed
perf(document): avoid unnecessarily pulling all subdocs when validating a subdoc
1 parent 0426329 commit 5851261

File tree

1 file changed

+35
-31
lines changed

1 file changed

+35
-31
lines changed

lib/document.js

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,7 +2689,7 @@ function _evaluateRequiredFunctions(doc) {
26892689
* ignore
26902690
*/
26912691

2692-
function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
2692+
function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate) {
26932693
const doValidateOptions = {};
26942694

26952695
_evaluateRequiredFunctions(doc);
@@ -2709,37 +2709,40 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
27092709
Object.keys(doc.$__.activePaths.getStatePaths('default')).forEach(addToPaths);
27102710
function addToPaths(p) { paths.add(p); }
27112711

2712-
const subdocs = doc.$getAllSubdocs();
2713-
const modifiedPaths = doc.modifiedPaths();
2714-
for (const subdoc of subdocs) {
2715-
if (subdoc.$basePath) {
2716-
const fullPathToSubdoc = subdoc.$isSingleNested ? subdoc.$__pathRelativeToParent() : subdoc.$__fullPathWithIndexes();
2717-
2718-
// Remove child paths for now, because we'll be validating the whole
2719-
// subdoc.
2720-
// The following is a faster take on looping through every path in `paths`
2721-
// and checking if the path starts with `fullPathToSubdoc` re: gh-13191
2722-
for (const modifiedPath of subdoc.modifiedPaths()) {
2723-
paths.delete(fullPathToSubdoc + '.' + modifiedPath);
2724-
}
2712+
if (!isNestedValidate) {
2713+
// If we're validating a subdocument, all this logic will run anyway on the top-level document, so skip for subdocuments
2714+
const subdocs = doc.$getAllSubdocs();
2715+
const modifiedPaths = doc.modifiedPaths();
2716+
for (const subdoc of subdocs) {
2717+
if (subdoc.$basePath) {
2718+
const fullPathToSubdoc = subdoc.$isSingleNested ? subdoc.$__pathRelativeToParent() : subdoc.$__fullPathWithIndexes();
2719+
2720+
// Remove child paths for now, because we'll be validating the whole
2721+
// subdoc.
2722+
// The following is a faster take on looping through every path in `paths`
2723+
// and checking if the path starts with `fullPathToSubdoc` re: gh-13191
2724+
for (const modifiedPath of subdoc.modifiedPaths()) {
2725+
paths.delete(fullPathToSubdoc + '.' + modifiedPath);
2726+
}
27252727

2726-
if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2727-
// Avoid using isDirectModified() here because that does additional checks on whether the parent path
2728-
// is direct modified, which can cause performance issues re: gh-14897
2729-
!doc.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2730-
!doc.$isDefault(fullPathToSubdoc)) {
2731-
paths.add(fullPathToSubdoc);
2728+
if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2729+
// Avoid using isDirectModified() here because that does additional checks on whether the parent path
2730+
// is direct modified, which can cause performance issues re: gh-14897
2731+
!doc.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2732+
!doc.$isDefault(fullPathToSubdoc)) {
2733+
paths.add(fullPathToSubdoc);
27322734

2733-
if (doc.$__.pathsToScopes == null) {
2734-
doc.$__.pathsToScopes = {};
2735-
}
2736-
doc.$__.pathsToScopes[fullPathToSubdoc] = subdoc.$isDocumentArrayElement ?
2737-
subdoc.__parentArray :
2738-
subdoc.$parent();
2735+
if (doc.$__.pathsToScopes == null) {
2736+
doc.$__.pathsToScopes = {};
2737+
}
2738+
doc.$__.pathsToScopes[fullPathToSubdoc] = subdoc.$isDocumentArrayElement ?
2739+
subdoc.__parentArray :
2740+
subdoc.$parent();
27392741

2740-
doValidateOptions[fullPathToSubdoc] = { skipSchemaValidators: true };
2741-
if (subdoc.$isDocumentArrayElement && subdoc.__index != null) {
2742-
doValidateOptions[fullPathToSubdoc].index = subdoc.__index;
2742+
doValidateOptions[fullPathToSubdoc] = { skipSchemaValidators: true };
2743+
if (subdoc.$isDocumentArrayElement && subdoc.__index != null) {
2744+
doValidateOptions[fullPathToSubdoc].index = subdoc.__index;
2745+
}
27432746
}
27442747
}
27452748
}
@@ -2974,7 +2977,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
29742977
paths = [...paths];
29752978
doValidateOptionsByPath = {};
29762979
} else {
2977-
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip);
2980+
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip, options && options._nestedValidate);
29782981
paths = shouldValidateModifiedOnly ?
29792982
pathDetails[0].filter((path) => this.$isModified(path)) :
29802983
pathDetails[0];
@@ -3061,7 +3064,8 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
30613064
const doValidateOptions = {
30623065
...doValidateOptionsByPath[path],
30633066
path: path,
3064-
validateAllPaths
3067+
validateAllPaths,
3068+
_nestedValidate: true
30653069
};
30663070

30673071
schemaType.doValidate(val, function(err) {

0 commit comments

Comments
 (0)