mongoose 8.19.4 → 9.0.0-rc0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.mjs +198 -0
- package/lib/aggregate.js +17 -73
- package/lib/cast/bigint.js +1 -1
- package/lib/cast/double.js +1 -1
- package/lib/cast/uuid.js +5 -48
- package/lib/cast.js +3 -3
- package/lib/connection.js +0 -1
- package/lib/cursor/aggregationCursor.js +14 -24
- package/lib/cursor/queryCursor.js +7 -14
- package/lib/document.js +125 -121
- package/lib/drivers/node-mongodb-native/connection.js +3 -10
- package/lib/error/divergentArray.js +2 -2
- package/lib/error/objectParameter.js +1 -2
- package/lib/error/validation.js +0 -8
- package/lib/helpers/clone.js +1 -1
- package/lib/helpers/common.js +1 -1
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +10 -0
- package/lib/helpers/indexes/isIndexEqual.js +0 -1
- package/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
- package/lib/helpers/model/applyHooks.js +43 -53
- package/lib/helpers/model/applyMethods.js +2 -2
- package/lib/helpers/model/applyStaticHooks.js +1 -48
- package/lib/helpers/model/castBulkWrite.js +1 -1
- package/lib/helpers/parallelLimit.js +18 -36
- package/lib/helpers/pluralize.js +3 -3
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -8
- package/lib/helpers/populate/createPopulateQueryFilter.js +1 -1
- package/lib/helpers/populate/getModelsMapForPopulate.js +17 -9
- package/lib/helpers/populate/getSchemaTypes.js +5 -5
- package/lib/helpers/query/cast$expr.js +8 -10
- package/lib/helpers/query/castFilterPath.js +1 -1
- package/lib/helpers/query/castUpdate.js +15 -13
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
- package/lib/helpers/schema/applyPlugins.js +1 -1
- package/lib/helpers/schema/getIndexes.js +1 -7
- package/lib/helpers/timestamps/setupTimestamps.js +3 -6
- package/lib/helpers/updateValidators.js +57 -111
- package/lib/model.js +419 -607
- package/lib/mongoose.js +41 -13
- package/lib/plugins/saveSubdocs.js +24 -51
- package/lib/plugins/sharding.js +5 -4
- package/lib/plugins/validateBeforeSave.js +3 -13
- package/lib/query.js +101 -145
- package/lib/queryHelpers.js +2 -2
- package/lib/schema/array.js +46 -84
- package/lib/schema/bigint.js +4 -2
- package/lib/schema/boolean.js +4 -2
- package/lib/schema/buffer.js +4 -2
- package/lib/schema/date.js +4 -2
- package/lib/schema/decimal128.js +4 -2
- package/lib/schema/documentArray.js +66 -91
- package/lib/schema/documentArrayElement.js +18 -11
- package/lib/schema/double.js +4 -2
- package/lib/schema/int32.js +4 -2
- package/lib/schema/map.js +87 -6
- package/lib/schema/mixed.js +4 -2
- package/lib/schema/number.js +4 -2
- package/lib/schema/objectId.js +4 -2
- package/lib/schema/string.js +5 -3
- package/lib/schema/subdocument.js +27 -31
- package/lib/schema/union.js +11 -3
- package/lib/schema/uuid.js +4 -23
- package/lib/schema.js +91 -91
- package/lib/schemaType.js +67 -59
- package/lib/types/array/index.js +2 -2
- package/lib/types/array/methods/index.js +4 -4
- package/lib/types/arraySubdocument.js +1 -1
- package/lib/types/buffer.js +10 -10
- package/lib/types/decimal128.js +1 -1
- package/lib/types/documentArray/index.js +1 -1
- package/lib/types/documentArray/methods/index.js +32 -18
- package/lib/types/double.js +1 -1
- package/lib/types/map.js +1 -2
- package/lib/types/objectid.js +1 -1
- package/lib/types/subdocument.js +15 -43
- package/lib/types/uuid.js +1 -1
- package/lib/utils.js +1 -8
- package/lib/validOptions.js +3 -3
- package/package.json +11 -24
- package/types/connection.d.ts +20 -11
- package/types/document.d.ts +96 -27
- package/types/index.d.ts +143 -39
- package/types/inferhydrateddoctype.d.ts +115 -0
- package/types/inferrawdoctype.d.ts +99 -75
- package/types/inferschematype.d.ts +17 -3
- package/types/middlewares.d.ts +0 -2
- package/types/models.d.ts +131 -199
- package/types/mongooseoptions.d.ts +6 -5
- package/types/pipelinestage.d.ts +1 -1
- package/types/query.d.ts +71 -139
- package/types/schemaoptions.d.ts +1 -1
- package/types/schematypes.d.ts +14 -10
- package/types/types.d.ts +3 -4
- package/types/utility.d.ts +68 -48
- package/types/validation.d.ts +18 -14
- package/browser.js +0 -8
- package/dist/browser.umd.js +0 -2
- package/lib/browser.js +0 -141
- package/lib/browserDocument.js +0 -101
- package/lib/documentProvider.js +0 -30
- package/lib/drivers/browser/binary.js +0 -14
- package/lib/drivers/browser/decimal128.js +0 -7
- package/lib/drivers/browser/index.js +0 -13
- package/lib/drivers/browser/objectid.js +0 -29
- package/lib/helpers/promiseOrCallback.js +0 -54
package/lib/model.js
CHANGED
|
@@ -104,7 +104,9 @@ const saveToObjectOptions = Object.assign({}, internalToObjectOptions, {
|
|
|
104
104
|
*
|
|
105
105
|
* @param {Object} doc values for initial set
|
|
106
106
|
* @param {Object} [fields] optional object containing the fields that were selected in the query which returned this document. You do **not** need to set this parameter to ensure Mongoose handles your [query projection](https://mongoosejs.com/docs/api/query.html#Query.prototype.select()).
|
|
107
|
-
* @param {
|
|
107
|
+
* @param {Object} [options] optional object containing the options for the document.
|
|
108
|
+
* @param {Boolean} [options.defaults=true] if `false`, skip applying default values to this document.
|
|
109
|
+
* @param {Boolean} [options.skipId=false] By default, Mongoose document if one is not provided and the document's schema does not override Mongoose's default `_id`. Set `skipId` to `true` to skip this generation step.
|
|
108
110
|
* @inherits Document https://mongoosejs.com/docs/api/document.html
|
|
109
111
|
* @event `error`: If listening to this event, 'error' is emitted when a document was saved and an `error` occurred. If not listening, the event bubbles to the connection used to create this Model.
|
|
110
112
|
* @event `index`: Emitted after `Model#ensureIndexes` completes. If an error occurred it is passed with the event.
|
|
@@ -113,7 +115,7 @@ const saveToObjectOptions = Object.assign({}, internalToObjectOptions, {
|
|
|
113
115
|
* @api public
|
|
114
116
|
*/
|
|
115
117
|
|
|
116
|
-
function Model(doc, fields,
|
|
118
|
+
function Model(doc, fields, options) {
|
|
117
119
|
if (fields instanceof Schema) {
|
|
118
120
|
throw new TypeError('2nd argument to `Model` constructor must be a POJO or string, ' +
|
|
119
121
|
'**not** a schema. Make sure you\'re calling `mongoose.model()`, not ' +
|
|
@@ -124,7 +126,7 @@ function Model(doc, fields, skipId) {
|
|
|
124
126
|
'**not** a string. Make sure you\'re calling `mongoose.model()`, not ' +
|
|
125
127
|
'`mongoose.Model()`.');
|
|
126
128
|
}
|
|
127
|
-
Document.call(this, doc, fields,
|
|
129
|
+
Document.call(this, doc, fields, options);
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
/**
|
|
@@ -316,11 +318,10 @@ function _applyCustomWhere(doc, where) {
|
|
|
316
318
|
/*!
|
|
317
319
|
* ignore
|
|
318
320
|
*/
|
|
319
|
-
|
|
320
|
-
Model.prototype.$__handleSave = function(options, callback) {
|
|
321
|
+
function _createSaveOptions(doc, options) {
|
|
321
322
|
const saveOptions = {};
|
|
322
323
|
|
|
323
|
-
applyWriteConcern(
|
|
324
|
+
applyWriteConcern(doc.$__schema, options);
|
|
324
325
|
if (typeof options.writeConcern !== 'undefined') {
|
|
325
326
|
saveOptions.writeConcern = {};
|
|
326
327
|
if ('w' in options.writeConcern) {
|
|
@@ -347,215 +348,180 @@ Model.prototype.$__handleSave = function(options, callback) {
|
|
|
347
348
|
saveOptions.checkKeys = options.checkKeys;
|
|
348
349
|
}
|
|
349
350
|
|
|
350
|
-
const session =
|
|
351
|
-
const asyncLocalStorage =
|
|
351
|
+
const session = doc.$session();
|
|
352
|
+
const asyncLocalStorage = doc[modelDbSymbol].base.transactionAsyncLocalStorage?.getStore();
|
|
352
353
|
if (session != null) {
|
|
353
354
|
saveOptions.session = session;
|
|
354
355
|
} else if (!options.hasOwnProperty('session') && asyncLocalStorage?.session != null) {
|
|
355
356
|
// Only set session from asyncLocalStorage if `session` option wasn't originally passed in options
|
|
356
357
|
saveOptions.session = asyncLocalStorage.session;
|
|
357
358
|
}
|
|
358
|
-
if (this.$isNew) {
|
|
359
|
-
// send entire doc
|
|
360
|
-
const obj = this.toObject(saveToObjectOptions);
|
|
361
|
-
if ((obj || {})._id === void 0) {
|
|
362
|
-
// documents must have an _id else mongoose won't know
|
|
363
|
-
// what to update later if more changes are made. the user
|
|
364
|
-
// wouldn't know what _id was generated by mongodb either
|
|
365
|
-
// nor would the ObjectId generated by mongodb necessarily
|
|
366
|
-
// match the schema definition.
|
|
367
|
-
immediate(function() {
|
|
368
|
-
callback(new MongooseError('document must have an _id before saving'));
|
|
369
|
-
});
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
359
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
ret => callback(null, ret),
|
|
376
|
-
err => {
|
|
377
|
-
_setIsNew(this, true);
|
|
360
|
+
return saveOptions;
|
|
361
|
+
}
|
|
378
362
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
363
|
+
/*!
|
|
364
|
+
* ignore
|
|
365
|
+
*/
|
|
382
366
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
367
|
+
Model.prototype.$__save = async function $__save(options) {
|
|
368
|
+
try {
|
|
369
|
+
await this._execDocumentPreHooks('save', options);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
await this._execDocumentPostHooks('save', error);
|
|
387
372
|
return;
|
|
388
373
|
}
|
|
389
374
|
|
|
390
|
-
// Make sure we don't treat it as a new object on error,
|
|
391
|
-
// since it already exists
|
|
392
|
-
this.$__.inserting = false;
|
|
393
|
-
const delta = this.$__delta();
|
|
394
375
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
376
|
+
let result = null;
|
|
377
|
+
let where = null;
|
|
378
|
+
try {
|
|
379
|
+
const saveOptions = _createSaveOptions(this, options);
|
|
380
|
+
|
|
381
|
+
if (this.$isNew) {
|
|
382
|
+
// send entire doc
|
|
383
|
+
const obj = this.toObject(saveToObjectOptions);
|
|
384
|
+
if ((obj || {})._id === void 0) {
|
|
385
|
+
// documents must have an _id else mongoose won't know
|
|
386
|
+
// what to update later if more changes are made. the user
|
|
387
|
+
// wouldn't know what _id was generated by mongodb either
|
|
388
|
+
// nor would the ObjectId generated by mongodb necessarily
|
|
389
|
+
// match the schema definition.
|
|
390
|
+
throw new MongooseError('document must have an _id before saving');
|
|
403
391
|
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
if (delta) {
|
|
407
|
-
if (delta instanceof MongooseError) {
|
|
408
|
-
callback(delta);
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
const where = this.$__where(delta[0]);
|
|
413
|
-
if (where instanceof MongooseError) {
|
|
414
|
-
callback(where);
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
_applyCustomWhere(this, where);
|
|
419
392
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
393
|
+
this.$__version(true, obj);
|
|
394
|
+
this.$__reset();
|
|
395
|
+
_setIsNew(this, false);
|
|
396
|
+
// Make it possible to retry the insert
|
|
397
|
+
this.$__.inserting = true;
|
|
398
|
+
result = await this[modelCollectionSymbol].insertOne(obj, saveOptions).catch(err => {
|
|
399
|
+
_setIsNew(this, true);
|
|
400
|
+
throw err;
|
|
401
|
+
});
|
|
402
|
+
} else {
|
|
403
|
+
// Make sure we don't treat it as a new object on error,
|
|
404
|
+
// since it already exists
|
|
405
|
+
this.$__.inserting = false;
|
|
406
|
+
const delta = this.$__delta();
|
|
407
|
+
|
|
408
|
+
if (options.pathsToSave) {
|
|
409
|
+
for (const key in delta[1]['$set']) {
|
|
410
|
+
if (options.pathsToSave.includes(key)) {
|
|
428
411
|
continue;
|
|
429
|
-
}
|
|
430
|
-
if (!utils.isPOJO(updateOp[key])) {
|
|
412
|
+
} else if (options.pathsToSave.some(pathToSave => key.slice(0, pathToSave.length) === pathToSave && key.charAt(pathToSave.length) === '.')) {
|
|
431
413
|
continue;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (Object.keys(updateOp[key]).length === 0) {
|
|
435
|
-
delete updateOp[key];
|
|
436
|
-
update.$unset = update.$unset || {};
|
|
437
|
-
update.$unset[key] = 1;
|
|
414
|
+
} else {
|
|
415
|
+
delete delta[1]['$set'][key];
|
|
438
416
|
}
|
|
439
417
|
}
|
|
440
418
|
}
|
|
441
|
-
|
|
419
|
+
if (delta) {
|
|
420
|
+
where = this.$__where(delta[0]);
|
|
421
|
+
_applyCustomWhere(this, where);
|
|
422
|
+
|
|
423
|
+
const update = delta[1];
|
|
424
|
+
if (this.$__schema.options.minimize) {
|
|
425
|
+
for (const updateOp of Object.values(update)) {
|
|
426
|
+
if (updateOp == null) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
for (const key of Object.keys(updateOp)) {
|
|
430
|
+
if (updateOp[key] == null || typeof updateOp[key] !== 'object') {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (!utils.isPOJO(updateOp[key])) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
minimize(updateOp[key]);
|
|
437
|
+
if (Object.keys(updateOp[key]).length === 0) {
|
|
438
|
+
delete updateOp[key];
|
|
439
|
+
update.$unset = update.$unset || {};
|
|
440
|
+
update.$unset[key] = 1;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
442
445
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
446
|
+
// store the modified paths before the document is reset
|
|
447
|
+
this.$__.modifiedPaths = this.modifiedPaths();
|
|
448
|
+
this.$__reset();
|
|
449
|
+
|
|
450
|
+
_setIsNew(this, false);
|
|
451
|
+
result = await this[modelCollectionSymbol].updateOne(where, update, saveOptions).catch(err => {
|
|
452
|
+
this.$__undoReset();
|
|
453
|
+
throw err;
|
|
454
|
+
});
|
|
455
|
+
} else {
|
|
456
|
+
where = this.$__where();
|
|
457
|
+
_applyCustomWhere(this, where);
|
|
458
|
+
if (this.$__.version) {
|
|
459
|
+
this.$__version(where, delta);
|
|
449
460
|
}
|
|
450
|
-
callback(null, ret);
|
|
451
|
-
},
|
|
452
|
-
err => {
|
|
453
|
-
this.$__undoReset();
|
|
454
461
|
|
|
455
|
-
|
|
462
|
+
applyReadConcern(this.$__schema, saveOptions);
|
|
463
|
+
result = await this.constructor.collection.findOne(where, saveOptions)
|
|
464
|
+
.then(documentExists => ({ matchedCount: !documentExists ? 0 : 1 }));
|
|
456
465
|
}
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
|
|
466
|
+
}
|
|
467
|
+
} catch (err) {
|
|
468
|
+
const error = this.$__schema._transformDuplicateKeyError(err);
|
|
469
|
+
await this._execDocumentPostHooks('save', error);
|
|
460
470
|
return;
|
|
461
471
|
}
|
|
462
472
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
473
|
+
let numAffected = 0;
|
|
474
|
+
const writeConcern = options != null ?
|
|
475
|
+
options.writeConcern != null ?
|
|
476
|
+
options.writeConcern.w :
|
|
477
|
+
options.w :
|
|
478
|
+
0;
|
|
479
|
+
if (writeConcern !== 0) {
|
|
480
|
+
// Skip checking if write succeeded if writeConcern is set to
|
|
481
|
+
// unacknowledged writes, because otherwise `numAffected` will always be 0
|
|
482
|
+
if (result != null) {
|
|
483
|
+
if (Array.isArray(result)) {
|
|
484
|
+
numAffected = result.length;
|
|
485
|
+
} else if (result.matchedCount != null) {
|
|
486
|
+
numAffected = result.matchedCount;
|
|
487
|
+
} else {
|
|
488
|
+
numAffected = result;
|
|
478
489
|
}
|
|
479
490
|
}
|
|
480
491
|
|
|
481
|
-
|
|
482
|
-
this
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
Model.prototype.$__save = function(options, callback) {
|
|
496
|
-
this.$__handleSave(options, (error, result) => {
|
|
497
|
-
if (error) {
|
|
498
|
-
error = this.$__schema._transformDuplicateKeyError(error);
|
|
499
|
-
const hooks = this.$__schema.s.hooks;
|
|
500
|
-
return hooks.execPost('save:error', this, [this], { error: error }, (error) => {
|
|
501
|
-
callback(error, this);
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
let numAffected = 0;
|
|
505
|
-
const writeConcern = options != null ?
|
|
506
|
-
options.writeConcern != null ?
|
|
507
|
-
options.writeConcern.w :
|
|
508
|
-
options.w :
|
|
509
|
-
0;
|
|
510
|
-
if (writeConcern !== 0) {
|
|
511
|
-
// Skip checking if write succeeded if writeConcern is set to
|
|
512
|
-
// unacknowledged writes, because otherwise `numAffected` will always be 0
|
|
513
|
-
if (result != null) {
|
|
514
|
-
if (Array.isArray(result)) {
|
|
515
|
-
numAffected = result.length;
|
|
516
|
-
} else if (result.matchedCount != null) {
|
|
517
|
-
numAffected = result.matchedCount;
|
|
518
|
-
} else {
|
|
519
|
-
numAffected = result;
|
|
520
|
-
}
|
|
492
|
+
const versionBump = this.$__.version;
|
|
493
|
+
// was this an update that required a version bump?
|
|
494
|
+
if (versionBump && !this.$__.inserting) {
|
|
495
|
+
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
|
|
496
|
+
this.$__.version = undefined;
|
|
497
|
+
const key = this.$__schema.options.versionKey;
|
|
498
|
+
const version = this.$__getValue(key) || 0;
|
|
499
|
+
if (numAffected <= 0) {
|
|
500
|
+
// the update failed. pass an error back
|
|
501
|
+
this.$__undoReset();
|
|
502
|
+
const err = this.$__.$versionError ||
|
|
503
|
+
new VersionError(this, version, this.$__.modifiedPaths);
|
|
504
|
+
await this._execDocumentPostHooks('save', err);
|
|
505
|
+
return;
|
|
521
506
|
}
|
|
522
507
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
|
|
527
|
-
this.$__.version = undefined;
|
|
528
|
-
const key = this.$__schema.options.versionKey;
|
|
529
|
-
const version = this.$__getValue(key) || 0;
|
|
530
|
-
if (numAffected <= 0) {
|
|
531
|
-
// the update failed. pass an error back
|
|
532
|
-
this.$__undoReset();
|
|
533
|
-
const err = this.$__.$versionError ||
|
|
534
|
-
new VersionError(this, version, this.$__.modifiedPaths);
|
|
535
|
-
return callback(err, this);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// increment version if was successful
|
|
539
|
-
if (doIncrement) {
|
|
540
|
-
this.$__setValue(key, version + 1);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
if (result != null && numAffected <= 0) {
|
|
544
|
-
this.$__undoReset();
|
|
545
|
-
error = new DocumentNotFoundError(result.$where,
|
|
546
|
-
this.constructor.modelName, numAffected, result);
|
|
547
|
-
const hooks = this.$__schema.s.hooks;
|
|
548
|
-
return hooks.execPost('save:error', this, [this], { error: error }, (error) => {
|
|
549
|
-
callback(error, this);
|
|
550
|
-
});
|
|
508
|
+
// increment version if was successful
|
|
509
|
+
if (doIncrement) {
|
|
510
|
+
this.$__setValue(key, version + 1);
|
|
551
511
|
}
|
|
552
512
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
513
|
+
if (result != null && numAffected <= 0) {
|
|
514
|
+
this.$__undoReset();
|
|
515
|
+
const error = new DocumentNotFoundError(where, this.constructor.modelName, numAffected, result);
|
|
516
|
+
await this._execDocumentPostHooks('save', error);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
this.$__.saving = undefined;
|
|
521
|
+
this.$__.savedState = {};
|
|
522
|
+
this.$emit('save', this, numAffected);
|
|
523
|
+
this.constructor.emit('save', this, numAffected);
|
|
524
|
+
await this._execDocumentPostHooks('save');
|
|
559
525
|
};
|
|
560
526
|
|
|
561
527
|
/*!
|
|
@@ -639,20 +605,17 @@ Model.prototype.save = async function save(options) {
|
|
|
639
605
|
|
|
640
606
|
this.$__.saveOptions = options;
|
|
641
607
|
|
|
642
|
-
|
|
643
|
-
this.$__save(options
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
resolve();
|
|
654
|
-
});
|
|
655
|
-
});
|
|
608
|
+
try {
|
|
609
|
+
await this.$__save(options);
|
|
610
|
+
} catch (error) {
|
|
611
|
+
this.$__handleReject(error);
|
|
612
|
+
throw error;
|
|
613
|
+
} finally {
|
|
614
|
+
this.$__.saving = null;
|
|
615
|
+
this.$__.saveOptions = null;
|
|
616
|
+
this.$__.$versionError = null;
|
|
617
|
+
this.$op = null;
|
|
618
|
+
}
|
|
656
619
|
|
|
657
620
|
return this;
|
|
658
621
|
};
|
|
@@ -750,7 +713,7 @@ Model.prototype.$__where = function _where(where) {
|
|
|
750
713
|
}
|
|
751
714
|
|
|
752
715
|
if (this._doc._id === void 0) {
|
|
753
|
-
|
|
716
|
+
throw new MongooseError('No _id found on document!');
|
|
754
717
|
}
|
|
755
718
|
|
|
756
719
|
return where;
|
|
@@ -791,9 +754,6 @@ Model.prototype.deleteOne = function deleteOne(options) {
|
|
|
791
754
|
|
|
792
755
|
const self = this;
|
|
793
756
|
const where = this.$__where();
|
|
794
|
-
if (where instanceof Error) {
|
|
795
|
-
throw where;
|
|
796
|
-
}
|
|
797
757
|
const query = self.constructor.deleteOne(where, options);
|
|
798
758
|
|
|
799
759
|
if (this.$session() != null) {
|
|
@@ -803,36 +763,32 @@ Model.prototype.deleteOne = function deleteOne(options) {
|
|
|
803
763
|
}
|
|
804
764
|
|
|
805
765
|
query.pre(async function queryPreDeleteOne() {
|
|
806
|
-
await
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
}
|
|
766
|
+
const res = await self.constructor._middleware.execPre('deleteOne', self, [self]);
|
|
767
|
+
// `self` is passed to pre hooks as argument for backwards compatibility, but that
|
|
768
|
+
// isn't the actual arguments passed to the wrapped function.
|
|
769
|
+
if (res?.length !== 1 || res[0] !== self) {
|
|
770
|
+
throw new Error('Document deleteOne pre hooks cannot overwrite arguments');
|
|
771
|
+
}
|
|
812
772
|
// Apply custom where conditions _after_ document deleteOne middleware for
|
|
813
773
|
// consistency with save() - sharding plugin needs to set $where
|
|
814
774
|
if (self.$where != null) {
|
|
815
775
|
this.where(self.$where);
|
|
816
776
|
}
|
|
777
|
+
return res;
|
|
817
778
|
});
|
|
818
|
-
query.pre(function callSubdocPreHooks(
|
|
819
|
-
|
|
820
|
-
subdoc.constructor._middleware.execPre('deleteOne', subdoc, [subdoc], cb);
|
|
821
|
-
}, cb);
|
|
779
|
+
query.pre(function callSubdocPreHooks() {
|
|
780
|
+
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPre('deleteOne', subdoc, [subdoc])));
|
|
822
781
|
});
|
|
823
|
-
query.pre(function skipIfAlreadyDeleted(
|
|
782
|
+
query.pre(function skipIfAlreadyDeleted() {
|
|
824
783
|
if (self.$__.isDeleted) {
|
|
825
|
-
|
|
784
|
+
throw new Kareem.skipWrappedFunction();
|
|
826
785
|
}
|
|
827
|
-
return cb();
|
|
828
786
|
});
|
|
829
|
-
query.post(function callSubdocPostHooks(
|
|
830
|
-
|
|
831
|
-
subdoc.constructor._middleware.execPost('deleteOne', subdoc, [subdoc], {}, cb);
|
|
832
|
-
}, cb);
|
|
787
|
+
query.post(function callSubdocPostHooks() {
|
|
788
|
+
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPost('deleteOne', subdoc, [subdoc])));
|
|
833
789
|
});
|
|
834
|
-
query.post(function queryPostDeleteOne(
|
|
835
|
-
self.constructor._middleware.execPost('deleteOne', self, [self], {}
|
|
790
|
+
query.post(function queryPostDeleteOne() {
|
|
791
|
+
return self.constructor._middleware.execPost('deleteOne', self, [self], {});
|
|
836
792
|
});
|
|
837
793
|
|
|
838
794
|
return query;
|
|
@@ -1183,16 +1139,11 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1183
1139
|
throw new MongooseError('Model.createCollection() no longer accepts a callback');
|
|
1184
1140
|
}
|
|
1185
1141
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
}
|
|
1192
|
-
return reject(err);
|
|
1193
|
-
}
|
|
1194
|
-
resolve();
|
|
1195
|
-
});
|
|
1142
|
+
[options] = await this.hooks.execPre('createCollection', this, [options]).catch(err => {
|
|
1143
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
1144
|
+
return [err];
|
|
1145
|
+
}
|
|
1146
|
+
throw err;
|
|
1196
1147
|
});
|
|
1197
1148
|
|
|
1198
1149
|
const collectionOptions = this &&
|
|
@@ -1248,31 +1199,16 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1248
1199
|
}
|
|
1249
1200
|
|
|
1250
1201
|
try {
|
|
1251
|
-
if (!
|
|
1202
|
+
if (!(options instanceof Kareem.skipWrappedFunction)) {
|
|
1252
1203
|
await this.db.createCollection(this.$__collection.collectionName, options);
|
|
1253
1204
|
}
|
|
1254
1205
|
} catch (err) {
|
|
1255
1206
|
if (err != null && (err.name !== 'MongoServerError' || err.code !== 48)) {
|
|
1256
|
-
await
|
|
1257
|
-
const _opts = { error: err };
|
|
1258
|
-
this.hooks.execPost('createCollection', this, [null], _opts, (err) => {
|
|
1259
|
-
if (err != null) {
|
|
1260
|
-
return reject(err);
|
|
1261
|
-
}
|
|
1262
|
-
resolve();
|
|
1263
|
-
});
|
|
1264
|
-
});
|
|
1207
|
+
await this.hooks.execPost('createCollection', this, [null], { error: err });
|
|
1265
1208
|
}
|
|
1266
1209
|
}
|
|
1267
1210
|
|
|
1268
|
-
await
|
|
1269
|
-
this.hooks.execPost('createCollection', this, [this.$__collection], (err) => {
|
|
1270
|
-
if (err != null) {
|
|
1271
|
-
return reject(err);
|
|
1272
|
-
}
|
|
1273
|
-
resolve();
|
|
1274
|
-
});
|
|
1275
|
-
});
|
|
1211
|
+
await this.hooks.execPost('createCollection', this, [this.$__collection]);
|
|
1276
1212
|
|
|
1277
1213
|
return this.$__collection;
|
|
1278
1214
|
};
|
|
@@ -1306,7 +1242,6 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1306
1242
|
* toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create
|
|
1307
1243
|
*
|
|
1308
1244
|
* @param {Object} [options] options to pass to `ensureIndexes()`
|
|
1309
|
-
* @param {Boolean} [options.background=null] if specified, overrides each index's `background` property
|
|
1310
1245
|
* @param {Boolean} [options.hideIndexes=false] set to `true` to hide indexes instead of dropping. Requires MongoDB server 4.4 or higher
|
|
1311
1246
|
* @return {Promise}
|
|
1312
1247
|
* @api public
|
|
@@ -1708,8 +1643,7 @@ function _ensureIndexes(model, options, callback) {
|
|
|
1708
1643
|
});
|
|
1709
1644
|
return;
|
|
1710
1645
|
}
|
|
1711
|
-
// Indexes are created one-by-one
|
|
1712
|
-
// with background indexes.
|
|
1646
|
+
// Indexes are created one-by-one
|
|
1713
1647
|
|
|
1714
1648
|
const indexSingleDone = function(err, fields, options, name) {
|
|
1715
1649
|
model.emit('index-single-done', err, fields, options, name);
|
|
@@ -1761,10 +1695,6 @@ function _ensureIndexes(model, options, callback) {
|
|
|
1761
1695
|
|
|
1762
1696
|
indexSingleStart(indexFields, options);
|
|
1763
1697
|
|
|
1764
|
-
if ('background' in options) {
|
|
1765
|
-
indexOptions.background = options.background;
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
1698
|
// Just in case `createIndex()` throws a sync error
|
|
1769
1699
|
let promise = null;
|
|
1770
1700
|
try {
|
|
@@ -2890,6 +2820,13 @@ Model.insertOne = async function insertOne(doc, options) {
|
|
|
2890
2820
|
Model.watch = function(pipeline, options) {
|
|
2891
2821
|
_checkContext(this, 'watch');
|
|
2892
2822
|
|
|
2823
|
+
options = options || {};
|
|
2824
|
+
const watchOptions = options?.hydrate !== undefined ?
|
|
2825
|
+
utils.omit(options, ['hydrate']) :
|
|
2826
|
+
{ ...options };
|
|
2827
|
+
options.model = this;
|
|
2828
|
+
|
|
2829
|
+
|
|
2893
2830
|
const changeStreamThunk = cb => {
|
|
2894
2831
|
pipeline = pipeline || [];
|
|
2895
2832
|
prepareDiscriminatorPipeline(pipeline, this.schema, 'fullDocument');
|
|
@@ -2898,18 +2835,15 @@ Model.watch = function(pipeline, options) {
|
|
|
2898
2835
|
if (this.closed) {
|
|
2899
2836
|
return;
|
|
2900
2837
|
}
|
|
2901
|
-
const driverChangeStream = this.$__collection.watch(pipeline,
|
|
2838
|
+
const driverChangeStream = this.$__collection.watch(pipeline, watchOptions);
|
|
2902
2839
|
cb(null, driverChangeStream);
|
|
2903
2840
|
});
|
|
2904
2841
|
} else {
|
|
2905
|
-
const driverChangeStream = this.$__collection.watch(pipeline,
|
|
2842
|
+
const driverChangeStream = this.$__collection.watch(pipeline, watchOptions);
|
|
2906
2843
|
cb(null, driverChangeStream);
|
|
2907
2844
|
}
|
|
2908
2845
|
};
|
|
2909
2846
|
|
|
2910
|
-
options = options || {};
|
|
2911
|
-
options.model = this;
|
|
2912
|
-
|
|
2913
2847
|
return new ChangeStream(changeStreamThunk, pipeline, options);
|
|
2914
2848
|
};
|
|
2915
2849
|
|
|
@@ -2995,37 +2929,14 @@ Model.insertMany = async function insertMany(arr, options) {
|
|
|
2995
2929
|
throw new MongooseError('Model.insertMany() no longer accepts a callback');
|
|
2996
2930
|
}
|
|
2997
2931
|
|
|
2998
|
-
|
|
2999
|
-
this
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
}
|
|
3003
|
-
resolve(res);
|
|
3004
|
-
});
|
|
3005
|
-
});
|
|
3006
|
-
};
|
|
3007
|
-
|
|
3008
|
-
/**
|
|
3009
|
-
* ignore
|
|
3010
|
-
*
|
|
3011
|
-
* @param {Array} arr
|
|
3012
|
-
* @param {Object} options
|
|
3013
|
-
* @param {Function} callback
|
|
3014
|
-
* @api private
|
|
3015
|
-
* @memberOf Model
|
|
3016
|
-
* @method $__insertMany
|
|
3017
|
-
* @static
|
|
3018
|
-
*/
|
|
3019
|
-
|
|
3020
|
-
Model.$__insertMany = function(arr, options, callback) {
|
|
3021
|
-
const _this = this;
|
|
3022
|
-
if (typeof options === 'function') {
|
|
3023
|
-
callback = options;
|
|
3024
|
-
options = null;
|
|
2932
|
+
try {
|
|
2933
|
+
[arr] = await this._middleware.execPre('insertMany', this, [arr]);
|
|
2934
|
+
} catch (error) {
|
|
2935
|
+
await this._middleware.execPost('insertMany', this, [arr], { error });
|
|
3025
2936
|
}
|
|
3026
2937
|
|
|
3027
|
-
callback = callback || utils.noop;
|
|
3028
2938
|
options = options || {};
|
|
2939
|
+
const ThisModel = this;
|
|
3029
2940
|
const limit = options.limit || 1000;
|
|
3030
2941
|
const rawResult = !!options.rawResult;
|
|
3031
2942
|
const ordered = typeof options.ordered === 'boolean' ? options.ordered : true;
|
|
@@ -3044,238 +2955,212 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3044
2955
|
const validationErrors = [];
|
|
3045
2956
|
const validationErrorsToOriginalOrder = new Map();
|
|
3046
2957
|
const results = ordered ? null : new Array(arr.length);
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
let createdNewDoc = false;
|
|
3057
|
-
if (!(doc instanceof _this)) {
|
|
3058
|
-
if (doc != null && typeof doc !== 'object') {
|
|
3059
|
-
return callback(new ObjectParameterError(doc, 'arr.' + index, 'insertMany'));
|
|
3060
|
-
}
|
|
3061
|
-
try {
|
|
3062
|
-
doc = new _this(doc);
|
|
3063
|
-
createdNewDoc = true;
|
|
3064
|
-
} catch (err) {
|
|
3065
|
-
return callback(err);
|
|
3066
|
-
}
|
|
2958
|
+
async function validateDoc(doc, index) {
|
|
2959
|
+
// If option `lean` is set to true bypass validation and hydration
|
|
2960
|
+
if (lean) {
|
|
2961
|
+
return doc;
|
|
2962
|
+
}
|
|
2963
|
+
let createdNewDoc = false;
|
|
2964
|
+
if (!(doc instanceof ThisModel)) {
|
|
2965
|
+
if (doc != null && typeof doc !== 'object') {
|
|
2966
|
+
throw new ObjectParameterError(doc, 'arr.' + index, 'insertMany');
|
|
3067
2967
|
}
|
|
2968
|
+
doc = new ThisModel(doc);
|
|
2969
|
+
createdNewDoc = true;
|
|
2970
|
+
}
|
|
3068
2971
|
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
error => {
|
|
3082
|
-
if (ordered === false) {
|
|
3083
|
-
// Add index to validation error so users can identify which document failed
|
|
3084
|
-
error.index = index;
|
|
3085
|
-
validationErrors.push(error);
|
|
3086
|
-
validationErrorsToOriginalOrder.set(error, index);
|
|
3087
|
-
results[index] = error;
|
|
3088
|
-
return callback(null, null);
|
|
3089
|
-
}
|
|
3090
|
-
callback(error);
|
|
2972
|
+
if (options.session != null) {
|
|
2973
|
+
doc.$session(options.session);
|
|
2974
|
+
}
|
|
2975
|
+
return doc.$validate(createdNewDoc ? { _skipParallelValidateCheck: true } : null)
|
|
2976
|
+
.then(() => doc)
|
|
2977
|
+
.catch(error => {
|
|
2978
|
+
if (ordered === false) {
|
|
2979
|
+
error.index = index;
|
|
2980
|
+
validationErrors.push(error);
|
|
2981
|
+
validationErrorsToOriginalOrder.set(error, index);
|
|
2982
|
+
results[index] = error;
|
|
2983
|
+
return;
|
|
3091
2984
|
}
|
|
3092
|
-
|
|
3093
|
-
|
|
2985
|
+
throw error;
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
3094
2988
|
|
|
3095
|
-
parallelLimit(
|
|
3096
|
-
if (error) {
|
|
3097
|
-
callback(error, null);
|
|
3098
|
-
return;
|
|
3099
|
-
}
|
|
2989
|
+
const docs = await parallelLimit(arr, validateDoc, limit);
|
|
3100
2990
|
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
2991
|
+
const originalDocIndex = new Map();
|
|
2992
|
+
const validDocIndexToOriginalIndex = new Map();
|
|
2993
|
+
for (let i = 0; i < docs.length; ++i) {
|
|
2994
|
+
originalDocIndex.set(docs[i], i);
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
// We filter all failed pre-validations by removing nulls
|
|
2998
|
+
const docAttributes = docs.filter(function(doc) {
|
|
2999
|
+
return doc != null;
|
|
3000
|
+
});
|
|
3001
|
+
for (let i = 0; i < docAttributes.length; ++i) {
|
|
3002
|
+
validDocIndexToOriginalIndex.set(i, originalDocIndex.get(docAttributes[i]));
|
|
3003
|
+
}
|
|
3106
3004
|
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3005
|
+
// Make sure validation errors are in the same order as the
|
|
3006
|
+
// original documents, so if both doc1 and doc2 both fail validation,
|
|
3007
|
+
// `Model.insertMany([doc1, doc2])` will always have doc1's validation
|
|
3008
|
+
// error before doc2's. Re: gh-12791.
|
|
3009
|
+
if (validationErrors.length > 0) {
|
|
3010
|
+
validationErrors.sort((err1, err2) => {
|
|
3011
|
+
return validationErrorsToOriginalOrder.get(err1) - validationErrorsToOriginalOrder.get(err2);
|
|
3110
3012
|
});
|
|
3111
|
-
|
|
3112
|
-
validDocIndexToOriginalIndex.set(i, originalDocIndex.get(docAttributes[i]));
|
|
3113
|
-
}
|
|
3013
|
+
}
|
|
3114
3014
|
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3015
|
+
// Quickly escape while there aren't any valid docAttributes
|
|
3016
|
+
if (docAttributes.length === 0) {
|
|
3017
|
+
if (throwOnValidationError) {
|
|
3018
|
+
throw new MongooseBulkWriteError(
|
|
3019
|
+
validationErrors,
|
|
3020
|
+
results,
|
|
3021
|
+
null,
|
|
3022
|
+
'insertMany'
|
|
3023
|
+
);
|
|
3123
3024
|
}
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
'insertMany'
|
|
3133
|
-
));
|
|
3134
|
-
}
|
|
3135
|
-
if (rawResult) {
|
|
3136
|
-
const res = {
|
|
3137
|
-
acknowledged: true,
|
|
3138
|
-
insertedCount: 0,
|
|
3139
|
-
insertedIds: {}
|
|
3140
|
-
};
|
|
3141
|
-
decorateBulkWriteResult(res, validationErrors, validationErrors);
|
|
3142
|
-
return callback(null, res);
|
|
3143
|
-
}
|
|
3144
|
-
callback(null, []);
|
|
3145
|
-
return;
|
|
3025
|
+
if (rawResult) {
|
|
3026
|
+
const res = {
|
|
3027
|
+
acknowledged: true,
|
|
3028
|
+
insertedCount: 0,
|
|
3029
|
+
insertedIds: {}
|
|
3030
|
+
};
|
|
3031
|
+
decorateBulkWriteResult(res, validationErrors, validationErrors);
|
|
3032
|
+
return res;
|
|
3146
3033
|
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
return doc
|
|
3159
|
-
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
res => {
|
|
3163
|
-
if (!lean) {
|
|
3164
|
-
for (const attribute of docAttributes) {
|
|
3165
|
-
attribute.$__reset();
|
|
3166
|
-
_setIsNew(attribute, false);
|
|
3167
|
-
}
|
|
3168
|
-
}
|
|
3034
|
+
return [];
|
|
3035
|
+
}
|
|
3036
|
+
const docObjects = lean ? docAttributes : docAttributes.map(function(doc) {
|
|
3037
|
+
if (doc.$__schema.options.versionKey) {
|
|
3038
|
+
doc[doc.$__schema.options.versionKey] = 0;
|
|
3039
|
+
}
|
|
3040
|
+
const shouldSetTimestamps = (!options || options.timestamps !== false) && doc.initializeTimestamps && (!doc.$__ || doc.$__.timestamps !== false);
|
|
3041
|
+
if (shouldSetTimestamps) {
|
|
3042
|
+
doc.initializeTimestamps();
|
|
3043
|
+
}
|
|
3044
|
+
if (doc.$__hasOnlyPrimitiveValues()) {
|
|
3045
|
+
return doc.$__toObjectShallow();
|
|
3046
|
+
}
|
|
3047
|
+
return doc.toObject(internalToObjectOptions);
|
|
3048
|
+
});
|
|
3169
3049
|
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
'insertMany'
|
|
3181
|
-
));
|
|
3182
|
-
}
|
|
3050
|
+
let res;
|
|
3051
|
+
try {
|
|
3052
|
+
res = await this.$__collection.insertMany(docObjects, options);
|
|
3053
|
+
} catch (error) {
|
|
3054
|
+
// `writeErrors` is a property reported by the MongoDB driver,
|
|
3055
|
+
// just not if there's only 1 error.
|
|
3056
|
+
if (error.writeErrors == null &&
|
|
3057
|
+
(error.result && error.result.result && error.result.result.writeErrors) != null) {
|
|
3058
|
+
error.writeErrors = error.result.result.writeErrors;
|
|
3059
|
+
}
|
|
3183
3060
|
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
if (results[i] === void 0) {
|
|
3188
|
-
results[i] = docs[i];
|
|
3189
|
-
}
|
|
3190
|
-
}
|
|
3061
|
+
// `insertedDocs` is a Mongoose-specific property
|
|
3062
|
+
const hasWriteErrors = error && error.writeErrors;
|
|
3063
|
+
const erroredIndexes = new Set((error && error.writeErrors || []).map(err => err.index));
|
|
3191
3064
|
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3065
|
+
if (error.writeErrors != null) {
|
|
3066
|
+
for (let i = 0; i < error.writeErrors.length; ++i) {
|
|
3067
|
+
const originalIndex = validDocIndexToOriginalIndex.get(error.writeErrors[i].index);
|
|
3068
|
+
error.writeErrors[i] = { ...error.writeErrors[i], index: originalIndex };
|
|
3069
|
+
if (!ordered) {
|
|
3070
|
+
results[originalIndex] = error.writeErrors[i];
|
|
3197
3071
|
}
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3198
3074
|
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
if (err != null) {
|
|
3204
|
-
err.insertedDocs = docAttributes;
|
|
3205
|
-
}
|
|
3206
|
-
throw err;
|
|
3207
|
-
}
|
|
3208
|
-
);
|
|
3075
|
+
if (!ordered) {
|
|
3076
|
+
for (let i = 0; i < results.length; ++i) {
|
|
3077
|
+
if (results[i] === void 0) {
|
|
3078
|
+
results[i] = docs[i];
|
|
3209
3079
|
}
|
|
3080
|
+
}
|
|
3210
3081
|
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
error => {
|
|
3214
|
-
// `writeErrors` is a property reported by the MongoDB driver,
|
|
3215
|
-
// just not if there's only 1 error.
|
|
3216
|
-
if (error.writeErrors == null &&
|
|
3217
|
-
(error.result && error.result.result && error.result.result.writeErrors) != null) {
|
|
3218
|
-
error.writeErrors = error.result.result.writeErrors;
|
|
3219
|
-
}
|
|
3082
|
+
error.results = results;
|
|
3083
|
+
}
|
|
3220
3084
|
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3085
|
+
let firstErroredIndex = -1;
|
|
3086
|
+
error.insertedDocs = docAttributes.
|
|
3087
|
+
filter((doc, i) => {
|
|
3088
|
+
const isErrored = !hasWriteErrors || erroredIndexes.has(i);
|
|
3224
3089
|
|
|
3225
|
-
if (
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
error.writeErrors[i] = { ...error.writeErrors[i], index: originalIndex };
|
|
3229
|
-
if (!ordered) {
|
|
3230
|
-
results[originalIndex] = error.writeErrors[i];
|
|
3231
|
-
}
|
|
3090
|
+
if (ordered) {
|
|
3091
|
+
if (firstErroredIndex > -1) {
|
|
3092
|
+
return i < firstErroredIndex;
|
|
3232
3093
|
}
|
|
3233
|
-
}
|
|
3234
3094
|
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
if (results[i] === void 0) {
|
|
3238
|
-
results[i] = docs[i];
|
|
3239
|
-
}
|
|
3095
|
+
if (isErrored) {
|
|
3096
|
+
firstErroredIndex = i;
|
|
3240
3097
|
}
|
|
3098
|
+
}
|
|
3241
3099
|
|
|
3242
|
-
|
|
3100
|
+
return !isErrored;
|
|
3101
|
+
}).
|
|
3102
|
+
map(function setIsNewForInsertedDoc(doc) {
|
|
3103
|
+
if (lean) {
|
|
3104
|
+
return doc;
|
|
3243
3105
|
}
|
|
3106
|
+
doc.$__reset();
|
|
3107
|
+
_setIsNew(doc, false);
|
|
3108
|
+
return doc;
|
|
3109
|
+
});
|
|
3244
3110
|
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
const isErrored = !hasWriteErrors || erroredIndexes.has(i);
|
|
3111
|
+
if (rawResult && ordered === false) {
|
|
3112
|
+
decorateBulkWriteResult(error, validationErrors, results);
|
|
3113
|
+
}
|
|
3249
3114
|
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
return i < firstErroredIndex;
|
|
3253
|
-
}
|
|
3115
|
+
await this._middleware.execPost('insertMany', this, [arr], { error });
|
|
3116
|
+
}
|
|
3254
3117
|
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3118
|
+
if (!lean) {
|
|
3119
|
+
for (const attribute of docAttributes) {
|
|
3120
|
+
attribute.$__reset();
|
|
3121
|
+
_setIsNew(attribute, false);
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3259
3124
|
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3125
|
+
if (ordered === false && throwOnValidationError && validationErrors.length > 0) {
|
|
3126
|
+
for (let i = 0; i < results.length; ++i) {
|
|
3127
|
+
if (results[i] === void 0) {
|
|
3128
|
+
results[i] = docs[i];
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
throw new MongooseBulkWriteError(
|
|
3132
|
+
validationErrors,
|
|
3133
|
+
results,
|
|
3134
|
+
res,
|
|
3135
|
+
'insertMany'
|
|
3136
|
+
);
|
|
3137
|
+
}
|
|
3270
3138
|
|
|
3271
|
-
|
|
3272
|
-
|
|
3139
|
+
if (rawResult) {
|
|
3140
|
+
if (ordered === false) {
|
|
3141
|
+
for (let i = 0; i < results.length; ++i) {
|
|
3142
|
+
if (results[i] === void 0) {
|
|
3143
|
+
results[i] = docs[i];
|
|
3273
3144
|
}
|
|
3145
|
+
}
|
|
3274
3146
|
|
|
3275
|
-
|
|
3147
|
+
// Decorate with mongoose validation errors in case of unordered,
|
|
3148
|
+
// because then still do `insertMany()`
|
|
3149
|
+
decorateBulkWriteResult(res, validationErrors, results);
|
|
3150
|
+
}
|
|
3151
|
+
return res;
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
if (options.populate != null) {
|
|
3155
|
+
return this.populate(docAttributes, options.populate).catch(err => {
|
|
3156
|
+
if (err != null) {
|
|
3157
|
+
err.insertedDocs = docAttributes;
|
|
3276
3158
|
}
|
|
3277
|
-
|
|
3278
|
-
|
|
3159
|
+
throw err;
|
|
3160
|
+
});
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
return await this._middleware.execPost('insertMany', this, [docAttributes]).then(res => res[0]);
|
|
3279
3164
|
};
|
|
3280
3165
|
|
|
3281
3166
|
/*!
|
|
@@ -3401,20 +3286,15 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3401
3286
|
}
|
|
3402
3287
|
options = options || {};
|
|
3403
3288
|
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
}
|
|
3410
|
-
return reject(err);
|
|
3411
|
-
}
|
|
3412
|
-
resolve();
|
|
3413
|
-
});
|
|
3289
|
+
[ops, options] = await this.hooks.execPre('bulkWrite', this, [ops, options]).catch(err => {
|
|
3290
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
3291
|
+
return [err];
|
|
3292
|
+
}
|
|
3293
|
+
throw err;
|
|
3414
3294
|
});
|
|
3415
3295
|
|
|
3416
|
-
if (
|
|
3417
|
-
return
|
|
3296
|
+
if (ops instanceof Kareem.skipWrappedFunction) {
|
|
3297
|
+
return ops.args[0];
|
|
3418
3298
|
}
|
|
3419
3299
|
|
|
3420
3300
|
const ordered = options.ordered == null ? true : options.ordered;
|
|
@@ -3448,15 +3328,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3448
3328
|
try {
|
|
3449
3329
|
res = await this.$__collection.bulkWrite(ops, options);
|
|
3450
3330
|
} catch (error) {
|
|
3451
|
-
await
|
|
3452
|
-
const _opts = { error: error };
|
|
3453
|
-
this.hooks.execPost('bulkWrite', this, [null], _opts, (err) => {
|
|
3454
|
-
if (err != null) {
|
|
3455
|
-
return reject(err);
|
|
3456
|
-
}
|
|
3457
|
-
resolve();
|
|
3458
|
-
});
|
|
3459
|
-
});
|
|
3331
|
+
await this.hooks.execPost('bulkWrite', this, [null], { error });
|
|
3460
3332
|
}
|
|
3461
3333
|
} else {
|
|
3462
3334
|
let validOpIndexes = [];
|
|
@@ -3525,15 +3397,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3525
3397
|
decorateBulkWriteResult(error, validationErrors, results);
|
|
3526
3398
|
}
|
|
3527
3399
|
|
|
3528
|
-
await
|
|
3529
|
-
const _opts = { error: error };
|
|
3530
|
-
this.hooks.execPost('bulkWrite', this, [null], _opts, (err) => {
|
|
3531
|
-
if (err != null) {
|
|
3532
|
-
return reject(err);
|
|
3533
|
-
}
|
|
3534
|
-
resolve();
|
|
3535
|
-
});
|
|
3536
|
-
});
|
|
3400
|
+
await this.hooks.execPost('bulkWrite', this, [null], { error });
|
|
3537
3401
|
}
|
|
3538
3402
|
|
|
3539
3403
|
if (validationErrors.length > 0) {
|
|
@@ -3550,14 +3414,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3550
3414
|
}
|
|
3551
3415
|
}
|
|
3552
3416
|
|
|
3553
|
-
await
|
|
3554
|
-
this.hooks.execPost('bulkWrite', this, [res], (err) => {
|
|
3555
|
-
if (err != null) {
|
|
3556
|
-
return reject(err);
|
|
3557
|
-
}
|
|
3558
|
-
resolve();
|
|
3559
|
-
});
|
|
3560
|
-
});
|
|
3417
|
+
await this.hooks.execPost('bulkWrite', this, [res]);
|
|
3561
3418
|
|
|
3562
3419
|
return res;
|
|
3563
3420
|
};
|
|
@@ -3647,34 +3504,20 @@ Model.bulkSave = async function bulkSave(documents, options) {
|
|
|
3647
3504
|
return bulkWriteResult;
|
|
3648
3505
|
};
|
|
3649
3506
|
|
|
3650
|
-
function buildPreSavePromise(document, options) {
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
return;
|
|
3656
|
-
}
|
|
3657
|
-
resolve();
|
|
3658
|
-
});
|
|
3659
|
-
});
|
|
3507
|
+
async function buildPreSavePromise(document, options) {
|
|
3508
|
+
const [newOptions] = await document.schema.s.hooks.execPre('save', document, [options]);
|
|
3509
|
+
if (newOptions !== options) {
|
|
3510
|
+
throw new Error('Cannot overwrite options in pre("save") hook on bulkSave()');
|
|
3511
|
+
}
|
|
3660
3512
|
}
|
|
3661
3513
|
|
|
3662
|
-
function handleSuccessfulWrite(document) {
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
}
|
|
3667
|
-
|
|
3668
|
-
document.$__reset();
|
|
3669
|
-
document.schema.s.hooks.execPost('save', document, [document], {}, (err) => {
|
|
3670
|
-
if (err) {
|
|
3671
|
-
reject(err);
|
|
3672
|
-
return;
|
|
3673
|
-
}
|
|
3674
|
-
resolve();
|
|
3675
|
-
});
|
|
3514
|
+
async function handleSuccessfulWrite(document) {
|
|
3515
|
+
if (document.$isNew) {
|
|
3516
|
+
_setIsNew(document, false);
|
|
3517
|
+
}
|
|
3676
3518
|
|
|
3677
|
-
|
|
3519
|
+
document.$__reset();
|
|
3520
|
+
return document.schema.s.hooks.execPost('save', document, [document]);
|
|
3678
3521
|
}
|
|
3679
3522
|
|
|
3680
3523
|
/**
|
|
@@ -3847,7 +3690,7 @@ Model.castObject = function castObject(obj, options) {
|
|
|
3847
3690
|
}
|
|
3848
3691
|
} else {
|
|
3849
3692
|
cur[pieces[pieces.length - 1]] = [
|
|
3850
|
-
Model.castObject.call(schemaType.
|
|
3693
|
+
Model.castObject.call(schemaType.Constructor, val)
|
|
3851
3694
|
];
|
|
3852
3695
|
}
|
|
3853
3696
|
|
|
@@ -3856,7 +3699,7 @@ Model.castObject = function castObject(obj, options) {
|
|
|
3856
3699
|
}
|
|
3857
3700
|
if (schemaType.$isSingleNested || schemaType.$isMongooseDocumentArrayElement) {
|
|
3858
3701
|
try {
|
|
3859
|
-
val = Model.castObject.call(schemaType.
|
|
3702
|
+
val = Model.castObject.call(schemaType.Constructor, val);
|
|
3860
3703
|
} catch (err) {
|
|
3861
3704
|
if (!options.ignoreCastErrors) {
|
|
3862
3705
|
error = error || new ValidationError();
|
|
@@ -4322,51 +4165,34 @@ Model.validate = async function validate(obj, pathsOrOptions, context) {
|
|
|
4322
4165
|
}
|
|
4323
4166
|
}
|
|
4324
4167
|
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
if (
|
|
4329
|
-
|
|
4168
|
+
const promises = [];
|
|
4169
|
+
for (const path of paths) {
|
|
4170
|
+
const schemaType = schema.path(path);
|
|
4171
|
+
if (schemaType == null) {
|
|
4172
|
+
continue;
|
|
4330
4173
|
}
|
|
4331
4174
|
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
continue;
|
|
4337
|
-
}
|
|
4338
|
-
|
|
4339
|
-
const pieces = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
4340
|
-
let cur = obj;
|
|
4341
|
-
for (let i = 0; i < pieces.length - 1; ++i) {
|
|
4342
|
-
cur = cur[pieces[i]];
|
|
4343
|
-
}
|
|
4344
|
-
|
|
4345
|
-
const val = get(obj, path, void 0);
|
|
4346
|
-
|
|
4347
|
-
schemaType.doValidate(val, err => {
|
|
4348
|
-
if (err) {
|
|
4349
|
-
error = error || new ValidationError();
|
|
4350
|
-
error.addError(path, err);
|
|
4351
|
-
}
|
|
4352
|
-
_checkDone();
|
|
4353
|
-
}, context, { path: path });
|
|
4175
|
+
const pieces = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
4176
|
+
let cur = obj;
|
|
4177
|
+
for (let i = 0; i < pieces.length - 1; ++i) {
|
|
4178
|
+
cur = cur[pieces[i]];
|
|
4354
4179
|
}
|
|
4355
4180
|
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
}
|
|
4362
|
-
|
|
4181
|
+
const val = get(obj, path, void 0);
|
|
4182
|
+
promises.push(
|
|
4183
|
+
schemaType.doValidate(val, context, { path: path }).catch(err => {
|
|
4184
|
+
error = error || new ValidationError();
|
|
4185
|
+
error.addError(path, err);
|
|
4186
|
+
})
|
|
4187
|
+
);
|
|
4188
|
+
}
|
|
4363
4189
|
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4190
|
+
await Promise.all(promises);
|
|
4191
|
+
if (error != null) {
|
|
4192
|
+
throw error;
|
|
4193
|
+
}
|
|
4194
|
+
|
|
4195
|
+
return obj;
|
|
4370
4196
|
};
|
|
4371
4197
|
|
|
4372
4198
|
/**
|
|
@@ -4736,14 +4562,7 @@ function _assign(model, vals, mod, assignmentOpts) {
|
|
|
4736
4562
|
if (__val instanceof Document) {
|
|
4737
4563
|
__val = __val._doc._id;
|
|
4738
4564
|
}
|
|
4739
|
-
|
|
4740
|
-
// Workaround for gh-15315 because Mongoose UUIDs don't use BSON UUIDs yet.
|
|
4741
|
-
key = String(__val.toUUID());
|
|
4742
|
-
} else if (__val?.constructor?.name === 'Buffer' && __val._subtype === 4 && typeof __val.toUUID === 'function') {
|
|
4743
|
-
key = String(__val.toUUID());
|
|
4744
|
-
} else {
|
|
4745
|
-
key = String(__val);
|
|
4746
|
-
}
|
|
4565
|
+
key = String(__val);
|
|
4747
4566
|
if (rawDocs[key]) {
|
|
4748
4567
|
if (Array.isArray(rawDocs[key])) {
|
|
4749
4568
|
rawDocs[key].push(val);
|
|
@@ -4766,14 +4585,7 @@ function _assign(model, vals, mod, assignmentOpts) {
|
|
|
4766
4585
|
if (_val instanceof Document) {
|
|
4767
4586
|
_val = _val._doc._id;
|
|
4768
4587
|
}
|
|
4769
|
-
|
|
4770
|
-
// Workaround for gh-15315 because Mongoose UUIDs don't use BSON UUIDs yet.
|
|
4771
|
-
key = String(_val.toUUID());
|
|
4772
|
-
} else if (_val?.constructor?.name === 'Buffer' && _val._subtype === 4 && typeof _val.toUUID === 'function') {
|
|
4773
|
-
key = String(_val.toUUID());
|
|
4774
|
-
} else {
|
|
4775
|
-
key = String(_val);
|
|
4776
|
-
}
|
|
4588
|
+
key = String(_val);
|
|
4777
4589
|
if (rawDocs[key]) {
|
|
4778
4590
|
if (Array.isArray(rawDocs[key])) {
|
|
4779
4591
|
rawDocs[key].push(val);
|