diff --git a/lib/document.js b/lib/document.js index caeb0e44176..07f0f962bc2 100644 --- a/lib/document.js +++ b/lib/document.js @@ -2642,7 +2642,7 @@ function _evaluateRequiredFunctions(doc) { */ function _getPathsToValidate(doc) { - const skipSchemaValidators = {}; + const doValidateOptions = {}; _evaluateRequiredFunctions(doc); // only validate required fields when necessary @@ -2679,8 +2679,17 @@ function _getPathsToValidate(doc) { !doc.isDirectModified(fullPathToSubdoc) && !doc.$isDefault(fullPathToSubdoc)) { paths.add(fullPathToSubdoc); + if (doc.$__.pathsToScopes == null) { + doc.$__.pathsToScopes = {}; + } + doc.$__.pathsToScopes[fullPathToSubdoc] = subdoc.$isDocumentArrayElement ? + subdoc.__parentArray : + subdoc.$parent(); - skipSchemaValidators[fullPathToSubdoc] = true; + doValidateOptions[fullPathToSubdoc] = { skipSchemaValidators: true }; + if (subdoc.$isDocumentArrayElement && subdoc.__index != null) { + doValidateOptions[fullPathToSubdoc].index = subdoc.__index; + } } } } @@ -2793,7 +2802,7 @@ function _getPathsToValidate(doc) { } paths = Array.from(paths); - return [paths, skipSchemaValidators]; + return [paths, doValidateOptions]; } /*! @@ -2864,7 +2873,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) { let paths = shouldValidateModifiedOnly ? pathDetails[0].filter((path) => this.$isModified(path)) : pathDetails[0]; - const skipSchemaValidators = pathDetails[1]; + const doValidateOptionsByPath = pathDetails[1]; if (typeof pathsToValidate === 'string') { pathsToValidate = pathsToValidate.split(' '); } @@ -2937,7 +2946,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) { _this; const doValidateOptions = { - skipSchemaValidators: skipSchemaValidators[path], + ...doValidateOptionsByPath[path], path: path, validateModifiedOnly: shouldValidateModifiedOnly }; @@ -2945,8 +2954,8 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) { schemaType.doValidate(val, function(err) { if (err) { const isSubdoc = schemaType.$isSingleNested || - schemaType.$isArraySubdocument || - schemaType.$isMongooseDocumentArray; + schemaType.$isArraySubdocument || + schemaType.$isMongooseDocumentArray; if (isSubdoc && err instanceof ValidationError) { return --total || complete(); } diff --git a/test/schema.validation.test.js b/test/schema.validation.test.js index 4d627786a2c..bfa3548bc57 100644 --- a/test/schema.validation.test.js +++ b/test/schema.validation.test.js @@ -1233,7 +1233,7 @@ describe('schema', function() { }); }); - it('enums on arrays (gh-6102) (gh-8449)', function() { + it('enums on arrays (gh-6102) (gh-8449)', async function() { assert.throws(function() { new Schema({ array: { @@ -1264,10 +1264,10 @@ describe('schema', function() { Model = mongoose.model('gh6102', MySchema); const doc2 = new Model({ array: [1, 2, 3] }); - return doc1.validate(). - then(() => assert.ok(false), err => assert.equal(err.name, 'ValidationError')). - then(() => doc2.validate()). - then(() => assert.ok(false), err => assert.equal(err.name, 'ValidationError')); + let err = await doc1.validate().then(() => null, err => err); + assert.equal(err.name, 'ValidationError'); + err = await doc2.validate().then(() => null, err => err); + assert.equal(err.name, 'ValidationError', err); }); it('skips conditional required (gh-3539)', function(done) {