Skip to content

Commit c8ccd90

Browse files
authored
Merge pull request #15735 from Jadu07/feat-insertmany-validation-error-context
feat: add index and doc to insertMany validation errors
2 parents a99ec8a + a6e4a36 commit c8ccd90

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

lib/model.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3076,6 +3076,8 @@ Model.$__insertMany = function(arr, options, callback) {
30763076
() => { callback(null, doc); },
30773077
error => {
30783078
if (ordered === false) {
3079+
// Add index to validation error so users can identify which document failed
3080+
error.index = index;
30793081
validationErrors.push(error);
30803082
validationErrorsToOriginalOrder.set(error, index);
30813083
results[index] = error;

test/model.insertMany.test.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,66 @@ describe('insertMany()', function() {
429429
assert.ok(!err.mongoose.validationErrors[1].errors['name']);
430430
});
431431

432+
it('insertMany() validation errors include index property with ordered false and rawResult', async function() {
433+
const schema = new Schema({
434+
title: { type: String, required: true },
435+
requiredField: { type: String, required: true }
436+
});
437+
const User = db.model('User', schema);
438+
439+
const arr = [
440+
{ title: 'title1', requiredField: 'field1' },
441+
{ title: 'title2' }, // Missing requiredField
442+
{ requiredField: 'field3' }, // Missing title
443+
{ title: 'title4', requiredField: 'field4' }
444+
];
445+
const opts = { ordered: false, rawResult: true };
446+
const res = await User.insertMany(arr, opts);
447+
448+
assert.equal(res.insertedCount, 2);
449+
assert.equal(res.mongoose.validationErrors.length, 2);
450+
451+
// Check first validation error (index 1)
452+
const error1 = res.mongoose.validationErrors[0];
453+
assert.equal(error1.index, 1);
454+
assert.ok(error1.errors['requiredField']);
455+
456+
// Check second validation error (index 2)
457+
const error2 = res.mongoose.validationErrors[1];
458+
assert.equal(error2.index, 2);
459+
assert.ok(error2.errors['title']);
460+
});
461+
462+
it('insertMany() validation errors include index property with throwOnValidationError', async function() {
463+
const schema = new Schema({
464+
title: { type: String, required: true },
465+
requiredField: { type: String, required: true }
466+
});
467+
const User = db.model('User', schema);
468+
469+
const arr = [
470+
{ title: 'title1', requiredField: 'field1' },
471+
{ title: 'title2' }, // Missing requiredField
472+
{ requiredField: 'field3' }, // Missing title
473+
{ title: 'title4', requiredField: 'field4' }
474+
];
475+
const opts = { ordered: false, rawResult: true, throwOnValidationError: true };
476+
const err = await User.insertMany(arr, opts).then(() => null, err => err);
477+
478+
assert.ok(err);
479+
assert.equal(err.validationErrors.length, 2);
480+
481+
// Check first validation error (index 1)
482+
const error1 = err.validationErrors[0];
483+
assert.equal(error1.index, 1);
484+
assert.ok(error1.errors['requiredField']);
485+
486+
// Check second validation error (index 2)
487+
const error2 = err.validationErrors[1];
488+
assert.equal(error2.index, 2);
489+
assert.ok(error2.errors['title']);
490+
});
491+
432492
it('insertMany() populate option (gh-9720)', async function() {
433493
const schema = new Schema({
434494
name: { type: String, required: true }

types/error.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ declare module 'mongoose' {
9191
errors: { [path: string]: ValidatorError | CastError };
9292
addError: (path: string, error: ValidatorError | CastError) => void;
9393

94+
/** Index of the document in insertMany() that failed validation (only set for unordered insertMany) */
95+
index?: number;
96+
9497
constructor(instance?: MongooseError);
9598
}
9699

0 commit comments

Comments
 (0)