@@ -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