mongoose 9.1.6 → 9.2.1
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/lib/aggregate.js +26 -12
- package/lib/cursor/aggregationCursor.js +1 -1
- package/lib/cursor/queryCursor.js +1 -1
- package/lib/document.js +25 -11
- package/lib/helpers/buildMiddlewareFilter.js +24 -0
- package/lib/helpers/clone.js +18 -0
- package/lib/helpers/model/applyHooks.js +12 -1
- package/lib/helpers/query/castUpdate.js +2 -2
- package/lib/helpers/timestamps/setupTimestamps.js +45 -29
- package/lib/model.js +93 -41
- package/lib/mongoose.js +21 -1
- package/lib/options.js +2 -1
- package/lib/plugins/saveSubdocs.js +85 -67
- package/lib/plugins/sharding.js +33 -16
- package/lib/plugins/trackTransaction.js +26 -21
- package/lib/plugins/validateBeforeSave.js +37 -31
- package/lib/query.js +69 -31
- package/lib/queryHelpers.js +9 -4
- package/lib/schema.js +11 -12
- package/lib/types/subdocument.js +10 -6
- package/lib/validOptions.js +1 -0
- package/package.json +5 -19
- package/types/aggregate.d.ts +2 -0
- package/types/document.d.ts +15 -100
- package/types/index.d.ts +93 -10
- package/types/inferrawdoctype.d.ts +13 -3
- package/types/inferschematype.d.ts +6 -1
- package/types/middlewares.d.ts +7 -0
- package/types/models.d.ts +10 -55
- package/types/mongooseoptions.d.ts +10 -6
- package/types/query.d.ts +24 -3
- package/types/types.d.ts +2 -2
- package/types/utility.d.ts +1 -1
- package/types/virtuals.d.ts +2 -2
package/lib/model.js
CHANGED
|
@@ -50,6 +50,7 @@ const immediate = require('./helpers/immediate');
|
|
|
50
50
|
const internalToObjectOptions = require('./options').internalToObjectOptions;
|
|
51
51
|
const isDefaultIdIndex = require('./helpers/indexes/isDefaultIdIndex');
|
|
52
52
|
const isIndexEqual = require('./helpers/indexes/isIndexEqual');
|
|
53
|
+
const isIndexSpecEqual = require('./helpers/indexes/isIndexSpecEqual');
|
|
53
54
|
const isTimeseriesIndex = require('./helpers/indexes/isTimeseriesIndex');
|
|
54
55
|
const {
|
|
55
56
|
getRelatedDBIndexes,
|
|
@@ -63,6 +64,7 @@ const prepareDiscriminatorPipeline = require('./helpers/aggregate/prepareDiscrim
|
|
|
63
64
|
const pushNestedArrayPaths = require('./helpers/model/pushNestedArrayPaths');
|
|
64
65
|
const removeDeselectedForeignField = require('./helpers/populate/removeDeselectedForeignField');
|
|
65
66
|
const setDottedPath = require('./helpers/path/setDottedPath');
|
|
67
|
+
const { buildMiddlewareFilter } = require('./helpers/buildMiddlewareFilter');
|
|
66
68
|
const util = require('util');
|
|
67
69
|
const utils = require('./utils');
|
|
68
70
|
const minimize = require('./helpers/minimize');
|
|
@@ -366,9 +368,9 @@ function _createSaveOptions(doc, options) {
|
|
|
366
368
|
|
|
367
369
|
Model.prototype.$__save = async function $__save(options) {
|
|
368
370
|
try {
|
|
369
|
-
await this._execDocumentPreHooks('save', options);
|
|
371
|
+
await this._execDocumentPreHooks('save', options, [options]);
|
|
370
372
|
} catch (error) {
|
|
371
|
-
await this._execDocumentPostHooks('save', error);
|
|
373
|
+
await this._execDocumentPostHooks('save', options, error);
|
|
372
374
|
return;
|
|
373
375
|
}
|
|
374
376
|
|
|
@@ -466,7 +468,7 @@ Model.prototype.$__save = async function $__save(options) {
|
|
|
466
468
|
}
|
|
467
469
|
} catch (err) {
|
|
468
470
|
const error = this.$__schema._transformDuplicateKeyError(err);
|
|
469
|
-
await this._execDocumentPostHooks('save', error);
|
|
471
|
+
await this._execDocumentPostHooks('save', options, error);
|
|
470
472
|
return;
|
|
471
473
|
}
|
|
472
474
|
|
|
@@ -501,7 +503,7 @@ Model.prototype.$__save = async function $__save(options) {
|
|
|
501
503
|
this.$__undoReset();
|
|
502
504
|
const err = this.$__.$versionError ||
|
|
503
505
|
new VersionError(this, version, this.$__.modifiedPaths);
|
|
504
|
-
await this._execDocumentPostHooks('save', err);
|
|
506
|
+
await this._execDocumentPostHooks('save', options, err);
|
|
505
507
|
return;
|
|
506
508
|
}
|
|
507
509
|
|
|
@@ -513,7 +515,7 @@ Model.prototype.$__save = async function $__save(options) {
|
|
|
513
515
|
if (result != null && numAffected <= 0) {
|
|
514
516
|
this.$__undoReset();
|
|
515
517
|
const error = new DocumentNotFoundError(where, this.constructor.modelName, numAffected, result);
|
|
516
|
-
await this._execDocumentPostHooks('save', error);
|
|
518
|
+
await this._execDocumentPostHooks('save', options, error);
|
|
517
519
|
return;
|
|
518
520
|
}
|
|
519
521
|
}
|
|
@@ -521,7 +523,7 @@ Model.prototype.$__save = async function $__save(options) {
|
|
|
521
523
|
this.$__.savedState = {};
|
|
522
524
|
this.$emit('save', this, numAffected);
|
|
523
525
|
this.constructor.emit('save', this, numAffected);
|
|
524
|
-
await this._execDocumentPostHooks('save');
|
|
526
|
+
await this._execDocumentPostHooks('save', options);
|
|
525
527
|
};
|
|
526
528
|
|
|
527
529
|
/*!
|
|
@@ -565,6 +567,9 @@ function generateVersionError(doc, modifiedPaths, defaultPaths) {
|
|
|
565
567
|
* @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Restrictions-on-Field-Names)
|
|
566
568
|
* @param {Boolean} [options.timestamps=true] if `false` and [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this `save()`.
|
|
567
569
|
* @param {Array} [options.pathsToSave] An array of paths that tell mongoose to only validate and save the paths in `pathsToSave`.
|
|
570
|
+
* @param {Boolean|Object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
571
|
+
* @param {Boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
572
|
+
* @param {Boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
568
573
|
* @throws {DocumentNotFoundError} if this [save updates an existing document](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew) but the document doesn't exist in the database. For example, you will get this error if the document is [deleted between when you retrieved the document and when you saved it](documents.html#updating).
|
|
569
574
|
* @return {Promise}
|
|
570
575
|
* @api public
|
|
@@ -762,8 +767,11 @@ Model.prototype.deleteOne = function deleteOne(options) {
|
|
|
762
767
|
}
|
|
763
768
|
}
|
|
764
769
|
|
|
770
|
+
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
771
|
+
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
772
|
+
|
|
765
773
|
query.pre(async function queryPreDeleteOne() {
|
|
766
|
-
const res = await self.constructor._middleware.execPre('deleteOne', self, [self, options]);
|
|
774
|
+
const res = await self.constructor._middleware.execPre('deleteOne', self, [self, options], { filter: preFilter });
|
|
767
775
|
// `self` is passed to pre hooks as argument for backwards compatibility, but that
|
|
768
776
|
// isn't the actual arguments passed to the wrapped function.
|
|
769
777
|
if (res[0] !== self || res[1] !== options) {
|
|
@@ -778,7 +786,7 @@ Model.prototype.deleteOne = function deleteOne(options) {
|
|
|
778
786
|
return res;
|
|
779
787
|
});
|
|
780
788
|
query.pre(function callSubdocPreHooks() {
|
|
781
|
-
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPre('deleteOne', subdoc, [subdoc])));
|
|
789
|
+
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPre('deleteOne', subdoc, [subdoc], { filter: preFilter })));
|
|
782
790
|
});
|
|
783
791
|
query.pre(function skipIfAlreadyDeleted() {
|
|
784
792
|
if (self.$__.isDeleted) {
|
|
@@ -786,10 +794,10 @@ Model.prototype.deleteOne = function deleteOne(options) {
|
|
|
786
794
|
}
|
|
787
795
|
});
|
|
788
796
|
query.post(function callSubdocPostHooks() {
|
|
789
|
-
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPost('deleteOne', subdoc, [subdoc])));
|
|
797
|
+
return Promise.all(self.$getAllSubdocs().map(subdoc => subdoc.constructor._middleware.execPost('deleteOne', subdoc, [subdoc], { filter: postFilter })));
|
|
790
798
|
});
|
|
791
799
|
query.post(function queryPostDeleteOne() {
|
|
792
|
-
return self.constructor._middleware.execPost('deleteOne', self, [self], {});
|
|
800
|
+
return self.constructor._middleware.execPost('deleteOne', self, [self], { filter: postFilter });
|
|
793
801
|
});
|
|
794
802
|
query.transform(function setIsDeleted(result) {
|
|
795
803
|
if (result?.deletedCount > 0) {
|
|
@@ -1146,7 +1154,16 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1146
1154
|
throw new MongooseError('Model.createCollection() no longer accepts a callback');
|
|
1147
1155
|
}
|
|
1148
1156
|
|
|
1149
|
-
|
|
1157
|
+
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
1158
|
+
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
1159
|
+
|
|
1160
|
+
// Remove middleware option before passing to MongoDB
|
|
1161
|
+
if (options?.middleware != null) {
|
|
1162
|
+
options = { ...options };
|
|
1163
|
+
delete options.middleware;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
[options] = await this.hooks.execPre('createCollection', this, [options], { filter: preFilter }).catch(err => {
|
|
1150
1167
|
if (err instanceof Kareem.skipWrappedFunction) {
|
|
1151
1168
|
return [err];
|
|
1152
1169
|
}
|
|
@@ -1196,11 +1213,11 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1196
1213
|
}
|
|
1197
1214
|
} catch (err) {
|
|
1198
1215
|
if (err != null && (err.name !== 'MongoServerError' || err.code !== 48)) {
|
|
1199
|
-
await this.hooks.execPost('createCollection', this, [null], { error: err });
|
|
1216
|
+
await this.hooks.execPost('createCollection', this, [null], { error: err, filter: postFilter });
|
|
1200
1217
|
}
|
|
1201
1218
|
}
|
|
1202
1219
|
|
|
1203
|
-
await this.hooks.execPost('createCollection', this, [this.$__collection]);
|
|
1220
|
+
await this.hooks.execPost('createCollection', this, [this.$__collection], { filter: postFilter });
|
|
1204
1221
|
|
|
1205
1222
|
return this.$__collection;
|
|
1206
1223
|
};
|
|
@@ -1629,6 +1646,25 @@ function _ensureIndexes(model, options, callback) {
|
|
|
1629
1646
|
}
|
|
1630
1647
|
}
|
|
1631
1648
|
|
|
1649
|
+
// Check for duplicate index definitions (gh-15056)
|
|
1650
|
+
const seenIndexes = [];
|
|
1651
|
+
for (const index of indexes) {
|
|
1652
|
+
const fields = index[0];
|
|
1653
|
+
const indexOptions = index[1];
|
|
1654
|
+
if (indexOptions.name == null) {
|
|
1655
|
+
for (const existingIndex of seenIndexes) {
|
|
1656
|
+
if (existingIndex[1].name == null && isIndexSpecEqual(existingIndex[0], fields)) {
|
|
1657
|
+
utils.warn('mongoose: Duplicate schema index on ' + JSON.stringify(fields) +
|
|
1658
|
+
' for model "' + model.modelName + '". ' +
|
|
1659
|
+
'This is often due to declaring an index using both "index: true" and "schema.index()". ' +
|
|
1660
|
+
'Please remove the duplicate index definition.');
|
|
1661
|
+
break;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
seenIndexes.push(index);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1632
1668
|
if (!indexes.length) {
|
|
1633
1669
|
immediate(function() {
|
|
1634
1670
|
done();
|
|
@@ -2296,10 +2332,10 @@ Model.$where = function $where() {
|
|
|
2296
2332
|
* @param {Object} [conditions]
|
|
2297
2333
|
* @param {Object} [update]
|
|
2298
2334
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
2299
|
-
* @param {
|
|
2335
|
+
* @param {'before'|'after'} [options.returnDocument='before'] Has two possible values, `'before'` and `'after'`. By default, it will return the document before the update was applied.
|
|
2300
2336
|
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and [the Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
|
|
2301
2337
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
2302
|
-
* @param {Boolean|
|
|
2338
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
2303
2339
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
|
|
2304
2340
|
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
2305
2341
|
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
|
|
@@ -2385,10 +2421,10 @@ Model.findOneAndUpdate = function(conditions, update, options) {
|
|
|
2385
2421
|
* @param {Object|Number|String} id value of `_id` to query by
|
|
2386
2422
|
* @param {Object} [update]
|
|
2387
2423
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
2388
|
-
* @param {
|
|
2424
|
+
* @param {'before'|'after'} [options.returnDocument='before'] Has two possible values, `'before'` and `'after'`. By default, it will return the document before the update was applied.
|
|
2389
2425
|
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and [the Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
|
|
2390
2426
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
2391
|
-
* @param {Boolean|
|
|
2427
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
2392
2428
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
|
|
2393
2429
|
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
|
|
2394
2430
|
* @param {Boolean} [options.runValidators] if true, runs [update validators](https://mongoosejs.com/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema
|
|
@@ -2446,7 +2482,7 @@ Model.findByIdAndUpdate = function(id, update, options) {
|
|
|
2446
2482
|
*
|
|
2447
2483
|
* @param {Object} conditions
|
|
2448
2484
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
2449
|
-
* @param {Boolean|
|
|
2485
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
2450
2486
|
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
|
|
2451
2487
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
2452
2488
|
* @param {Boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html) rather than just the document
|
|
@@ -2488,7 +2524,7 @@ Model.findOneAndDelete = function(conditions, options) {
|
|
|
2488
2524
|
*
|
|
2489
2525
|
* @param {Object|Number|String} id value of `_id` to query by
|
|
2490
2526
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
2491
|
-
* @param {Boolean|
|
|
2527
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
2492
2528
|
* @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
|
|
2493
2529
|
* @return {Query}
|
|
2494
2530
|
* @see Model.findOneAndDelete https://mongoosejs.com/docs/api/model.html#Model.findOneAndDelete()
|
|
@@ -2523,10 +2559,10 @@ Model.findByIdAndDelete = function(id, options) {
|
|
|
2523
2559
|
* @param {Object} filter Replace the first document that matches this filter
|
|
2524
2560
|
* @param {Object} [replacement] Replace with this document
|
|
2525
2561
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
2526
|
-
* @param {
|
|
2562
|
+
* @param {'before'|'after'} [options.returnDocument='before'] Has two possible values, `'before'` and `'after'`. By default, it will return the document before the update was applied.
|
|
2527
2563
|
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and [the Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
|
|
2528
2564
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
2529
|
-
* @param {Boolean|
|
|
2565
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
2530
2566
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
|
|
2531
2567
|
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
|
|
2532
2568
|
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
|
|
@@ -2910,6 +2946,9 @@ Model.startSession = function() {
|
|
|
2910
2946
|
* @param {Number} [options.limit=null] this limits the number of documents being processed (validation/casting) by mongoose in parallel, this does **NOT** send the documents in batches to MongoDB. Use this option if you're processing a large number of documents and your app is running out of memory.
|
|
2911
2947
|
* @param {String|Object|Array} [options.populate=null] populates the result documents. This option is a no-op if `rawResult` is set.
|
|
2912
2948
|
* @param {Boolean} [options.throwOnValidationError=false] If true and `ordered: false`, throw an error if one of the operations failed validation, but all valid operations completed successfully.
|
|
2949
|
+
* @param {Boolean|Object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
2950
|
+
* @param {Boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
2951
|
+
* @param {Boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
2913
2952
|
* @return {Promise} resolving to the raw result from the MongoDB driver if `options.rawResult` was `true`, or the documents that passed validation, otherwise
|
|
2914
2953
|
* @api public
|
|
2915
2954
|
*/
|
|
@@ -2921,13 +2960,15 @@ Model.insertMany = async function insertMany(arr, options) {
|
|
|
2921
2960
|
throw new MongooseError('Model.insertMany() no longer accepts a callback');
|
|
2922
2961
|
}
|
|
2923
2962
|
|
|
2963
|
+
options = options || {};
|
|
2964
|
+
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
2965
|
+
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
2966
|
+
|
|
2924
2967
|
try {
|
|
2925
|
-
[arr] = await this._middleware.execPre('insertMany', this, [arr]);
|
|
2968
|
+
[arr] = await this._middleware.execPre('insertMany', this, [arr], { filter: preFilter });
|
|
2926
2969
|
} catch (error) {
|
|
2927
|
-
await this._middleware.execPost('insertMany', this, [arr], { error });
|
|
2970
|
+
await this._middleware.execPost('insertMany', this, [arr], { error, filter: postFilter });
|
|
2928
2971
|
}
|
|
2929
|
-
|
|
2930
|
-
options = options || {};
|
|
2931
2972
|
const ThisModel = this;
|
|
2932
2973
|
const limit = options.limit || 1000;
|
|
2933
2974
|
const rawResult = !!options.rawResult;
|
|
@@ -3104,7 +3145,7 @@ Model.insertMany = async function insertMany(arr, options) {
|
|
|
3104
3145
|
decorateBulkWriteResult(error, validationErrors, results);
|
|
3105
3146
|
}
|
|
3106
3147
|
|
|
3107
|
-
await this._middleware.execPost('insertMany', this, [arr], { error });
|
|
3148
|
+
await this._middleware.execPost('insertMany', this, [arr], { error, filter: postFilter });
|
|
3108
3149
|
}
|
|
3109
3150
|
|
|
3110
3151
|
if (!lean) {
|
|
@@ -3152,7 +3193,8 @@ Model.insertMany = async function insertMany(arr, options) {
|
|
|
3152
3193
|
});
|
|
3153
3194
|
}
|
|
3154
3195
|
|
|
3155
|
-
|
|
3196
|
+
const [result] = await this._middleware.execPost('insertMany', this, [docAttributes], { filter: postFilter });
|
|
3197
|
+
return result;
|
|
3156
3198
|
};
|
|
3157
3199
|
|
|
3158
3200
|
/*!
|
|
@@ -3267,6 +3309,9 @@ function _setIsNew(doc, val) {
|
|
|
3267
3309
|
* @param {Boolean} [options.bypassDocumentValidation=false] If true, disable [MongoDB server-side schema validation](https://www.mongodb.com/docs/manual/core/schema-validation/) for all writes in this bulk.
|
|
3268
3310
|
* @param {Boolean} [options.throwOnValidationError=false] If true and `ordered: false`, throw an error if one of the operations failed validation, but all valid operations completed successfully. Note that Mongoose will still send all valid operations to the MongoDB server.
|
|
3269
3311
|
* @param {Boolean|"throw"} [options.strict=null] Overwrites the [`strict` option](https://mongoosejs.com/docs/guide.html#strict) on schema. If false, allows filtering and writing fields not defined in the schema for all writes in this bulk.
|
|
3312
|
+
* @param {Boolean|Object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
3313
|
+
* @param {Boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
3314
|
+
* @param {Boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
3270
3315
|
* @return {Promise} resolves to a [`BulkWriteOpResult`](https://mongodb.github.io/node-mongodb-native/4.9/classes/BulkWriteResult.html) if the operation succeeds
|
|
3271
3316
|
* @api public
|
|
3272
3317
|
*/
|
|
@@ -3279,14 +3324,16 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3279
3324
|
throw new MongooseError('Model.bulkWrite() no longer accepts a callback');
|
|
3280
3325
|
}
|
|
3281
3326
|
options = options || {};
|
|
3327
|
+
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
3328
|
+
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
3282
3329
|
|
|
3283
3330
|
try {
|
|
3284
|
-
[ops, options] = await this.hooks.execPre('bulkWrite', this, [ops, options]);
|
|
3331
|
+
[ops, options] = await this.hooks.execPre('bulkWrite', this, [ops, options], { filter: preFilter });
|
|
3285
3332
|
} catch (err) {
|
|
3286
3333
|
if (err instanceof Kareem.skipWrappedFunction) {
|
|
3287
3334
|
ops = err;
|
|
3288
3335
|
} else {
|
|
3289
|
-
await this.hooks.execPost('bulkWrite', this, [null], { error: err });
|
|
3336
|
+
await this.hooks.execPost('bulkWrite', this, [null], { error: err, filter: postFilter });
|
|
3290
3337
|
}
|
|
3291
3338
|
}
|
|
3292
3339
|
|
|
@@ -3325,7 +3372,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3325
3372
|
try {
|
|
3326
3373
|
res = await this.$__collection.bulkWrite(ops, options);
|
|
3327
3374
|
} catch (error) {
|
|
3328
|
-
await this.hooks.execPost('bulkWrite', this, [null], { error });
|
|
3375
|
+
await this.hooks.execPost('bulkWrite', this, [null], { error, filter: postFilter });
|
|
3329
3376
|
}
|
|
3330
3377
|
} else {
|
|
3331
3378
|
let validOpIndexes = [];
|
|
@@ -3394,7 +3441,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3394
3441
|
decorateBulkWriteResult(error, validationErrors, results);
|
|
3395
3442
|
}
|
|
3396
3443
|
|
|
3397
|
-
await this.hooks.execPost('bulkWrite', this, [null], { error });
|
|
3444
|
+
await this.hooks.execPost('bulkWrite', this, [null], { error, filter: postFilter });
|
|
3398
3445
|
}
|
|
3399
3446
|
|
|
3400
3447
|
if (validationErrors.length > 0) {
|
|
@@ -3411,7 +3458,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3411
3458
|
}
|
|
3412
3459
|
}
|
|
3413
3460
|
|
|
3414
|
-
await this.hooks.execPost('bulkWrite', this, [res]);
|
|
3461
|
+
await this.hooks.execPost('bulkWrite', this, [res], { filter: postFilter });
|
|
3415
3462
|
|
|
3416
3463
|
return res;
|
|
3417
3464
|
};
|
|
@@ -3438,6 +3485,9 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3438
3485
|
* @param {number} [options.wtimeout=null] The [write concern timeout](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout).
|
|
3439
3486
|
* @param {Boolean} [options.j=true] If false, disable [journal acknowledgement](https://www.mongodb.com/docs/manual/reference/write-concern/#j-option)
|
|
3440
3487
|
* @param {Boolean} [options.validateBeforeSave=true] set to `false` to skip Mongoose validation on all documents
|
|
3488
|
+
* @param {Boolean|Object} [options.middleware=true] set to `false` to skip all user-defined middleware
|
|
3489
|
+
* @param {Boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
|
|
3490
|
+
* @param {Boolean} [options.middleware.post=true] set to `false` to skip only post hooks
|
|
3441
3491
|
* @return {BulkWriteResult} the return value from `bulkWrite()`
|
|
3442
3492
|
*/
|
|
3443
3493
|
Model.bulkSave = async function bulkSave(documents, options) {
|
|
@@ -3492,7 +3542,7 @@ Model.bulkSave = async function bulkSave(documents, options) {
|
|
|
3492
3542
|
successfulDocuments.push(document);
|
|
3493
3543
|
}
|
|
3494
3544
|
}
|
|
3495
|
-
await Promise.all(successfulDocuments.map(document => handleSuccessfulWrite(document)));
|
|
3545
|
+
await Promise.all(successfulDocuments.map(document => handleSuccessfulWrite(document, options)));
|
|
3496
3546
|
|
|
3497
3547
|
if (bulkWriteError != null) {
|
|
3498
3548
|
throw bulkWriteError;
|
|
@@ -3502,20 +3552,22 @@ Model.bulkSave = async function bulkSave(documents, options) {
|
|
|
3502
3552
|
};
|
|
3503
3553
|
|
|
3504
3554
|
async function buildPreSavePromise(document, options) {
|
|
3505
|
-
const
|
|
3555
|
+
const preFilter = buildMiddlewareFilter(options, 'pre');
|
|
3556
|
+
const [newOptions] = await document.schema.s.hooks.execPre('save', document, [options], { filter: preFilter });
|
|
3506
3557
|
if (newOptions !== options) {
|
|
3507
3558
|
throw new Error('Cannot overwrite options in pre("save") hook on bulkSave()');
|
|
3508
3559
|
}
|
|
3509
3560
|
}
|
|
3510
3561
|
|
|
3511
|
-
async function handleSuccessfulWrite(document) {
|
|
3562
|
+
async function handleSuccessfulWrite(document, options) {
|
|
3512
3563
|
if (document.$isNew) {
|
|
3513
3564
|
_setIsNew(document, false);
|
|
3514
3565
|
}
|
|
3515
3566
|
|
|
3516
3567
|
document.$__reset();
|
|
3517
3568
|
document._applyVersionIncrement();
|
|
3518
|
-
|
|
3569
|
+
const postFilter = buildMiddlewareFilter(options, 'post');
|
|
3570
|
+
return document.schema.s.hooks.execPost('save', document, [document], { filter: postFilter });
|
|
3519
3571
|
}
|
|
3520
3572
|
|
|
3521
3573
|
/**
|
|
@@ -3824,7 +3876,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
|
|
|
3824
3876
|
* @param {Boolean} [options.setters=false] if true, apply schema setters when hydrating
|
|
3825
3877
|
* @param {Boolean} [options.hydratedPopulatedDocs=false] if true, populates the docs if passing pre-populated data
|
|
3826
3878
|
* @param {Boolean} [options.virtuals=false] if true, sets any virtuals present on `obj`
|
|
3827
|
-
* @param {Boolean|
|
|
3879
|
+
* @param {Boolean|'throw'} [options.strict=false] configure strict mode for the hydrated document. In particular, if strict is false, fields not in the schema won't be stripped out; if strict is 'throw', `hydrate()` will throw an error if there are any fields that are not in the schema. Defaults to true (silently strip out fields not in the schema).
|
|
3828
3880
|
* @return {Document} document instance
|
|
3829
3881
|
* @api public
|
|
3830
3882
|
*/
|
|
@@ -3875,7 +3927,7 @@ Model.hydrate = function(obj, projection, options) {
|
|
|
3875
3927
|
* @param {Object} filter
|
|
3876
3928
|
* @param {Object|Array} update. If array, this update will be treated as an update pipeline and not casted.
|
|
3877
3929
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
3878
|
-
* @param {Boolean|
|
|
3930
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
3879
3931
|
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3880
3932
|
* @param {Object} [options.writeConcern=null] sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](https://mongoosejs.com/docs/guide.html#writeConcern)
|
|
3881
3933
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
|
|
@@ -3923,7 +3975,7 @@ Model.updateMany = function updateMany(conditions, update, options) {
|
|
|
3923
3975
|
* @param {Object} filter
|
|
3924
3976
|
* @param {Object|Array} update. If array, this update will be treated as an update pipeline and not casted.
|
|
3925
3977
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
3926
|
-
* @param {Boolean|
|
|
3978
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
3927
3979
|
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3928
3980
|
* @param {Object} [options.writeConcern=null] sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](https://mongoosejs.com/docs/guide.html#writeConcern)
|
|
3929
3981
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
|
|
@@ -3961,7 +4013,7 @@ Model.updateOne = function updateOne(conditions, doc, options) {
|
|
|
3961
4013
|
* @param {Object} filter
|
|
3962
4014
|
* @param {Object} doc
|
|
3963
4015
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
3964
|
-
* @param {Boolean|
|
|
4016
|
+
* @param {Boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
3965
4017
|
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
3966
4018
|
* @param {Object} [options.writeConcern=null] sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](https://mongoosejs.com/docs/guide.html#writeConcern)
|
|
3967
4019
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
|
|
@@ -4002,7 +4054,7 @@ function _update(model, op, conditions, doc, options) {
|
|
|
4002
4054
|
}
|
|
4003
4055
|
options = typeof options === 'function' ? options : clone(options);
|
|
4004
4056
|
|
|
4005
|
-
const versionKey = model?.schema?.options?.versionKey
|
|
4057
|
+
const versionKey = model?.schema?.options?.versionKey ?? null;
|
|
4006
4058
|
decorateUpdateWithVersionKey(doc, options, versionKey);
|
|
4007
4059
|
|
|
4008
4060
|
return mq[op](conditions, doc, options);
|
package/lib/mongoose.js
CHANGED
|
@@ -233,7 +233,8 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
|
233
233
|
* - `maxTimeMS`: If set, attaches [maxTimeMS](https://www.mongodb.com/docs/manual/reference/operator/meta/maxTimeMS/) to every query
|
|
234
234
|
* - `objectIdGetter`: `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
|
|
235
235
|
* - `overwriteModels`: Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
|
|
236
|
-
* - `
|
|
236
|
+
* - `returnDocument`: Set to `'before'` or `'after'` to set the default value for the `returnDocument` option to `findOneAndUpdate()`, `findByIdAndUpdate()`, and `findOneAndReplace()`. Defaults to `'before'`, which returns the document before the update was applied. Read our [`findOneAndUpdate()` tutorial](https://mongoosejs.com/docs/tutorials/findoneandupdate.html) for more information.
|
|
237
|
+
* - `returnOriginal`: **Deprecated.** Use `returnDocument` instead. If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](https://mongoosejs.com/docs/tutorials/findoneandupdate.html) for more information.
|
|
237
238
|
* - `runValidators`: `false` by default. Set to true to enable [update validators](https://mongoosejs.com/docs/validation.html#update-validators) for all validators by default.
|
|
238
239
|
* - `sanitizeFilter`: `false` by default. Set to true to enable the [sanitization of the query filters](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.sanitizeFilter()) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
|
|
239
240
|
* - `selectPopulatedPaths`: `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
|
|
@@ -242,6 +243,8 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
|
242
243
|
* - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.immutable) which means you can update the `createdAt`
|
|
243
244
|
* - `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toJSON()), for determining how Mongoose documents get serialized by `JSON.stringify()`
|
|
244
245
|
* - `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject())
|
|
246
|
+
* - `transactionAsyncLocalStorage`: `false` by default. If `true`, Mongoose will automatically pass the `session` to any operation executing within a transaction executor function. See [transaction AsyncLocalStorage documentation](https://mongoosejs.com/docs/transactions.html#asynclocalstorage)
|
|
247
|
+
* - `translateAliases`: `false` by default. If `true`, Mongoose will automatically translate aliases to their original paths before sending the query to MongoDB.
|
|
245
248
|
* - `updatePipeline`: `false` by default. If `true`, allows passing update pipelines (arrays) to update operations by default without explicitly setting `updatePipeline: true` in each query.
|
|
246
249
|
*
|
|
247
250
|
* @param {String|Object} key The name of the option or a object of multiple key-value pairs
|
|
@@ -313,6 +316,23 @@ Mongoose.prototype.set = function getsetOptions(key, value) {
|
|
|
313
316
|
_mongoose.connections.shift();
|
|
314
317
|
}
|
|
315
318
|
}
|
|
319
|
+
} else if (optionKey === 'returnOriginal') {
|
|
320
|
+
if (_mongoose.options.returnDocument != null) {
|
|
321
|
+
throw new MongooseError(
|
|
322
|
+
'Cannot set `returnOriginal` when `returnDocument` is already set. Use `returnDocument` instead.'
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
const replacement = optionValue === true ? '\'before\'' : '\'after\'';
|
|
326
|
+
utils.warn(
|
|
327
|
+
'Mongoose: the `returnOriginal` option for `mongoose.set()` is deprecated. ' +
|
|
328
|
+
'Use `mongoose.set(\'returnDocument\', ' + replacement + ')` instead.'
|
|
329
|
+
);
|
|
330
|
+
} else if (optionKey === 'returnDocument') {
|
|
331
|
+
if (_mongoose.options.returnOriginal != null) {
|
|
332
|
+
throw new MongooseError(
|
|
333
|
+
'Cannot set `returnDocument` when `returnOriginal` is already set. Use `returnDocument` instead of `returnOriginal`.'
|
|
334
|
+
);
|
|
335
|
+
}
|
|
316
336
|
}
|
|
317
337
|
}
|
|
318
338
|
|
package/lib/options.js
CHANGED
|
@@ -1,76 +1,94 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const symbols = require('../schema/symbols');
|
|
4
|
+
|
|
3
5
|
/*!
|
|
4
6
|
* ignore
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
9
|
module.exports = function saveSubdocs(schema) {
|
|
8
10
|
const unshift = true;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const subdocs = this.$getAllSubdocs({ useCache: true });
|
|
15
|
-
|
|
16
|
-
if (!subdocs.length) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const options = this.$__.saveOptions;
|
|
21
|
-
await Promise.all(subdocs.map(subdoc => subdoc._execDocumentPreHooks('save', options)));
|
|
22
|
-
|
|
23
|
-
// Invalidate subdocs cache because subdoc pre hooks can add new subdocuments
|
|
24
|
-
if (this.$__.saveOptions) {
|
|
25
|
-
this.$__.saveOptions.__subdocs = null;
|
|
26
|
-
}
|
|
27
|
-
}, null, unshift);
|
|
28
|
-
|
|
29
|
-
schema.s.hooks.pre('save', async function saveSubdocsPreDeleteOne() {
|
|
30
|
-
const removedSubdocs = this.$__.removedSubdocs;
|
|
31
|
-
if (!removedSubdocs?.length) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const promises = [];
|
|
36
|
-
for (const subdoc of removedSubdocs) {
|
|
37
|
-
promises.push(subdoc._execDocumentPreHooks('deleteOne'));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
await Promise.all(promises);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
schema.s.hooks.post('save', async function saveSubdocsPostDeleteOne() {
|
|
44
|
-
const removedSubdocs = this.$__.removedSubdocs;
|
|
45
|
-
if (!removedSubdocs?.length) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const promises = [];
|
|
50
|
-
for (const subdoc of removedSubdocs) {
|
|
51
|
-
promises.push(subdoc._execDocumentPostHooks('deleteOne'));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.$__.removedSubdocs = null;
|
|
55
|
-
await Promise.all(promises);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
schema.s.hooks.post('save', async function saveSubdocsPostSave() {
|
|
59
|
-
if (this.$isSubdocument) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const subdocs = this.$getAllSubdocs({ useCache: true });
|
|
64
|
-
|
|
65
|
-
if (!subdocs.length) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const promises = [];
|
|
70
|
-
for (const subdoc of subdocs) {
|
|
71
|
-
promises.push(subdoc._execDocumentPostHooks('save'));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await Promise.all(promises);
|
|
75
|
-
}, null, unshift);
|
|
11
|
+
|
|
12
|
+
schema.s.hooks.pre('save', false, saveSubdocsPreSave, null, unshift);
|
|
13
|
+
schema.s.hooks.post('save', saveSubdocsPostSave, null, unshift);
|
|
14
|
+
schema.s.hooks.pre('save', saveSubdocsPreDeleteOne);
|
|
15
|
+
schema.s.hooks.post('save', saveSubdocsPostDeleteOne);
|
|
76
16
|
};
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async function saveSubdocsPreSave() {
|
|
20
|
+
if (this.$isSubdocument) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const subdocs = this.$getAllSubdocs({ useCache: true });
|
|
25
|
+
|
|
26
|
+
if (!subdocs.length) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const options = this.$__.saveOptions;
|
|
31
|
+
await Promise.all(subdocs.map(subdoc => subdoc._execDocumentPreHooks('save', options, [options])));
|
|
32
|
+
|
|
33
|
+
// Invalidate subdocs cache because subdoc pre hooks can add new subdocuments
|
|
34
|
+
if (this.$__.saveOptions) {
|
|
35
|
+
this.$__.saveOptions.__subdocs = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function saveSubdocsPostSave() {
|
|
40
|
+
if (this.$isSubdocument) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const subdocs = this.$getAllSubdocs({ useCache: true });
|
|
45
|
+
|
|
46
|
+
if (!subdocs.length) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const options = this.$__.saveOptions;
|
|
51
|
+
const promises = [];
|
|
52
|
+
for (const subdoc of subdocs) {
|
|
53
|
+
promises.push(subdoc._execDocumentPostHooks('save', options));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await Promise.all(promises);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function saveSubdocsPreDeleteOne() {
|
|
60
|
+
const removedSubdocs = this.$__.removedSubdocs;
|
|
61
|
+
if (!removedSubdocs?.length) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const options = this.$__.saveOptions;
|
|
66
|
+
const promises = [];
|
|
67
|
+
for (const subdoc of removedSubdocs) {
|
|
68
|
+
promises.push(subdoc._execDocumentPreHooks('deleteOne', options));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await Promise.all(promises);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function saveSubdocsPostDeleteOne() {
|
|
75
|
+
const removedSubdocs = this.$__.removedSubdocs;
|
|
76
|
+
if (!removedSubdocs?.length) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const options = this.$__.saveOptions;
|
|
81
|
+
const promises = [];
|
|
82
|
+
for (const subdoc of removedSubdocs) {
|
|
83
|
+
promises.push(subdoc._execDocumentPostHooks('deleteOne', options));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.$__.removedSubdocs = null;
|
|
87
|
+
await Promise.all(promises);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
saveSubdocsPreSave[symbols.builtInMiddleware] = true;
|
|
92
|
+
saveSubdocsPostSave[symbols.builtInMiddleware] = true;
|
|
93
|
+
saveSubdocsPreDeleteOne[symbols.builtInMiddleware] = true;
|
|
94
|
+
saveSubdocsPostDeleteOne[symbols.builtInMiddleware] = true;
|