@depup/mongoose 9.3.3-depup.0 → 9.8.0-depup.0
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/README.md +3 -9
- package/changes.json +3 -8
- package/eslint.config.mjs +4 -1
- package/lib/aggregate.js +54 -24
- package/lib/cast.js +1 -1
- package/lib/connection.js +20 -8
- package/lib/cursor/aggregationCursor.js +47 -16
- package/lib/cursor/queryCursor.js +23 -7
- package/lib/document.js +240 -105
- package/lib/drivers/node-mongodb-native/collection.js +47 -14
- package/lib/drivers/node-mongodb-native/connection.js +13 -0
- package/lib/error/cast.js +18 -9
- package/lib/error/divergentArray.js +1 -1
- package/lib/error/index.js +1 -1
- package/lib/error/messages.js +1 -0
- package/lib/helpers/clone.js +22 -5
- package/lib/helpers/document/applyDefaults.js +5 -0
- package/lib/helpers/populate/createPopulateQueryFilter.js +9 -1
- package/lib/helpers/populate/getModelsMapForPopulate.js +8 -6
- package/lib/helpers/populate/splitPopulateQuery.js +81 -0
- package/lib/helpers/query/castUpdate.js +4 -0
- package/lib/helpers/schema/getKeysInSchemaOrder.js +13 -16
- package/lib/helpers/update/applyTimestampsToUpdate.js +4 -2
- package/lib/model.js +159 -41
- package/lib/mongoose.js +3 -3
- package/lib/options/schemaTypeOptions.js +14 -0
- package/lib/plugins/saveSubdocs.js +16 -13
- package/lib/query.js +208 -102
- package/lib/queryHelpers.js +13 -12
- package/lib/schema/array.js +4 -6
- package/lib/schema/bigint.js +1 -3
- package/lib/schema/boolean.js +1 -3
- package/lib/schema/buffer.js +1 -3
- package/lib/schema/date.js +8 -8
- package/lib/schema/decimal128.js +1 -3
- package/lib/schema/documentArray.js +3 -5
- package/lib/schema/double.js +1 -3
- package/lib/schema/int32.js +1 -3
- package/lib/schema/map.js +1 -4
- package/lib/schema/number.js +2 -4
- package/lib/schema/objectId.js +7 -3
- package/lib/schema/string.js +20 -5
- package/lib/schema/subdocument.js +2 -4
- package/lib/schema/union.js +50 -0
- package/lib/schema/uuid.js +1 -3
- package/lib/schema.js +40 -14
- package/lib/schemaType.js +93 -12
- package/lib/standardSchema/convertErrorToIssues.js +20 -0
- package/lib/stateMachine.js +11 -6
- package/lib/tracing.js +38 -0
- package/lib/types/array/methods/index.js +4 -4
- package/lib/types/documentArray/methods/index.js +117 -3
- package/lib/types/subdocument.js +4 -2
- package/lib/utils.js +12 -2
- package/lib/validOptions.js +1 -0
- package/package.json +30 -33
- package/{tstyche.config.json → tstyche.json} +2 -1
- package/types/augmentations.d.ts +2 -2
- package/types/document.d.ts +61 -7
- package/types/expressions.d.ts +16 -0
- package/types/index.d.ts +25 -7
- package/types/inferhydrateddoctype.d.ts +1 -1
- package/types/inferrawdoctype.d.ts +6 -3
- package/types/inferschematype.d.ts +10 -2
- package/types/models.d.ts +30 -13
- package/types/mongooseoptions.d.ts +9 -1
- package/types/populate.d.ts +52 -0
- package/types/query.d.ts +39 -12
- package/types/schemaoptions.d.ts +5 -0
- package/types/schematypes.d.ts +10 -0
- package/types/tracing.d.ts +10 -0
- package/types/utility.d.ts +11 -2
- package/lib/helpers/createJSONSchemaTypeDefinition.js +0 -24
package/lib/query.js
CHANGED
|
@@ -20,6 +20,7 @@ const castArrayFilters = require('./helpers/update/castArrayFilters');
|
|
|
20
20
|
const castNumber = require('./cast/number');
|
|
21
21
|
const castUpdate = require('./helpers/query/castUpdate');
|
|
22
22
|
const clone = require('./helpers/clone');
|
|
23
|
+
const decorateUpdateWithVersionKey = require('./helpers/update/decorateUpdateWithVersionKey');
|
|
23
24
|
const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
|
|
24
25
|
const helpers = require('./queryHelpers');
|
|
25
26
|
const internalToObjectOptions = require('./options').internalToObjectOptions;
|
|
@@ -41,6 +42,8 @@ const updateValidators = require('./helpers/updateValidators');
|
|
|
41
42
|
const util = require('util');
|
|
42
43
|
const utils = require('./utils');
|
|
43
44
|
const queryMiddlewareFunctions = require('./constants').queryMiddlewareFunctions;
|
|
45
|
+
const { createTracedChannel } = require('./tracing');
|
|
46
|
+
const { trace: traceQuery } = createTracedChannel('mongoose:query');
|
|
44
47
|
|
|
45
48
|
const queryOptionMethods = new Set([
|
|
46
49
|
'allowDiskUse',
|
|
@@ -85,6 +88,8 @@ const opToThunk = new Map([
|
|
|
85
88
|
['findOneAndDelete', '_findOneAndDelete']
|
|
86
89
|
]);
|
|
87
90
|
|
|
91
|
+
const queryUpdateSymbol = Symbol('mongoose#Query#update');
|
|
92
|
+
|
|
88
93
|
/**
|
|
89
94
|
* Query constructor used for building queries. You do not need
|
|
90
95
|
* to instantiate a `Query` directly. Instead use Model functions like
|
|
@@ -196,6 +201,18 @@ function checkRequireFilter(filter, options) {
|
|
|
196
201
|
Query.prototype = new mquery();
|
|
197
202
|
Query.prototype.constructor = Query;
|
|
198
203
|
|
|
204
|
+
Object.defineProperty(Query.prototype, '_update', {
|
|
205
|
+
configurable: true,
|
|
206
|
+
enumerable: true,
|
|
207
|
+
get: function() {
|
|
208
|
+
_cloneUpdateIfShared(this);
|
|
209
|
+
return this[queryUpdateSymbol];
|
|
210
|
+
},
|
|
211
|
+
set: function(v) {
|
|
212
|
+
this[queryUpdateSymbol] = v;
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
199
216
|
// Remove some legacy methods that we removed in Mongoose 8, but
|
|
200
217
|
// are still in mquery 5.
|
|
201
218
|
Query.prototype.count = undefined;
|
|
@@ -300,7 +317,7 @@ Query.prototype.toConstructor = function toConstructor() {
|
|
|
300
317
|
p.op = this.op;
|
|
301
318
|
p._conditions = clone(this._conditions);
|
|
302
319
|
p._fields = clone(this._fields);
|
|
303
|
-
p
|
|
320
|
+
p[queryUpdateSymbol] = clone(this[queryUpdateSymbol], {
|
|
304
321
|
flattenDecimals: false
|
|
305
322
|
});
|
|
306
323
|
p._path = this._path;
|
|
@@ -348,7 +365,7 @@ Query.prototype.clone = function() {
|
|
|
348
365
|
q.op = this.op;
|
|
349
366
|
q._conditions = clone(this._conditions);
|
|
350
367
|
q._fields = clone(this._fields);
|
|
351
|
-
q
|
|
368
|
+
q[queryUpdateSymbol] = clone(this[queryUpdateSymbol], {
|
|
352
369
|
flattenDecimals: false
|
|
353
370
|
});
|
|
354
371
|
q._path = this._path;
|
|
@@ -1365,7 +1382,7 @@ Query.prototype.toString = function toString() {
|
|
|
1365
1382
|
this.op === 'update' ||
|
|
1366
1383
|
this.op === 'updateMany' ||
|
|
1367
1384
|
this.op === 'updateOne') {
|
|
1368
|
-
return `${this.model.modelName}.${this.op}(${util.inspect(this._conditions)}, ${util.inspect(this
|
|
1385
|
+
return `${this.model.modelName}.${this.op}(${util.inspect(this._conditions)}, ${util.inspect(this[queryUpdateSymbol])})`;
|
|
1369
1386
|
}
|
|
1370
1387
|
|
|
1371
1388
|
// 'estimatedDocumentCount' or any others
|
|
@@ -1669,6 +1686,7 @@ Query.prototype.getOptions = function() {
|
|
|
1669
1686
|
* - [upsert](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
|
|
1670
1687
|
* - [writeConcern](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/)
|
|
1671
1688
|
* - [timestamps](https://mongoosejs.com/docs/guide.html#timestamps): If `timestamps` is set in the schema, set this option to `false` to skip timestamps for that particular update. Has no effect if `timestamps` is not enabled in the schema options.
|
|
1689
|
+
* - cloneUpdate: set to `false` to skip cloning the update before executing the query.
|
|
1672
1690
|
* - overwriteDiscriminatorKey: allow setting the discriminator key in the update. Will use the correct discriminator schema if the update changes the discriminator key.
|
|
1673
1691
|
* - overwriteImmutable: allow overwriting properties that are set to `immutable` in the schema. Defaults to false.
|
|
1674
1692
|
*
|
|
@@ -1679,6 +1697,7 @@ Query.prototype.getOptions = function() {
|
|
|
1679
1697
|
* - [projection](https://mongoosejs.com/docs/api/query.html#Query.prototype.projection())
|
|
1680
1698
|
* - sanitizeProjection
|
|
1681
1699
|
* - useBigInt64
|
|
1700
|
+
* - defaults: if `false`, skip applying default values to the returned document(s). Defaults to true.
|
|
1682
1701
|
*
|
|
1683
1702
|
* The following options are only for all operations **except** `updateOne()`, `updateMany()`, `deleteOne()`, and `deleteMany()`:
|
|
1684
1703
|
*
|
|
@@ -1751,6 +1770,10 @@ Query.prototype.setOptions = function(options, overwrite) {
|
|
|
1751
1770
|
this._mongooseOptions.updatePipeline = options.updatePipeline;
|
|
1752
1771
|
delete options.updatePipeline;
|
|
1753
1772
|
}
|
|
1773
|
+
if ('cloneUpdate' in options) {
|
|
1774
|
+
this._mongooseOptions.cloneUpdate = options.cloneUpdate;
|
|
1775
|
+
delete options.cloneUpdate;
|
|
1776
|
+
}
|
|
1754
1777
|
if ('sanitizeProjection' in options) {
|
|
1755
1778
|
if (options.sanitizeProjection && !this._mongooseOptions.sanitizeProjection) {
|
|
1756
1779
|
sanitizeProjection(this._fields);
|
|
@@ -1984,12 +2007,17 @@ Query.prototype.getUpdate = function() {
|
|
|
1984
2007
|
* query.getUpdate(); // { $set: { b: 6 } }
|
|
1985
2008
|
*
|
|
1986
2009
|
* @param {object} new update operation
|
|
2010
|
+
* @param {boolean} [cloneUpdate=true] if `false`, Mongoose will not clone the update
|
|
1987
2011
|
* @return {undefined}
|
|
1988
2012
|
* @api public
|
|
1989
2013
|
*/
|
|
1990
2014
|
|
|
1991
|
-
Query.prototype.setUpdate = function(val) {
|
|
1992
|
-
this
|
|
2015
|
+
Query.prototype.setUpdate = function(val, cloneUpdate) {
|
|
2016
|
+
this[queryUpdateSymbol] = cloneUpdate === false ? val : clone(val);
|
|
2017
|
+
if (cloneUpdate != null) {
|
|
2018
|
+
this._mongooseOptions.cloneUpdate = cloneUpdate;
|
|
2019
|
+
}
|
|
2020
|
+
this._updateIsShared = false;
|
|
1993
2021
|
};
|
|
1994
2022
|
|
|
1995
2023
|
/**
|
|
@@ -2022,7 +2050,7 @@ Query.prototype._fieldsForExec = function() {
|
|
|
2022
2050
|
*/
|
|
2023
2051
|
|
|
2024
2052
|
Query.prototype._updateForExec = function() {
|
|
2025
|
-
const update = clone(this
|
|
2053
|
+
const update = clone(this[queryUpdateSymbol], {
|
|
2026
2054
|
transform: false,
|
|
2027
2055
|
depopulate: true
|
|
2028
2056
|
});
|
|
@@ -2216,6 +2244,8 @@ Query.prototype.lean = function(v) {
|
|
|
2216
2244
|
*/
|
|
2217
2245
|
|
|
2218
2246
|
Query.prototype.set = function(path, val) {
|
|
2247
|
+
_cloneUpdateIfShared(this);
|
|
2248
|
+
|
|
2219
2249
|
if (typeof path === 'object') {
|
|
2220
2250
|
const keys = Object.keys(path);
|
|
2221
2251
|
for (const key of keys) {
|
|
@@ -2224,12 +2254,16 @@ Query.prototype.set = function(path, val) {
|
|
|
2224
2254
|
return this;
|
|
2225
2255
|
}
|
|
2226
2256
|
|
|
2227
|
-
|
|
2228
|
-
if (
|
|
2229
|
-
|
|
2257
|
+
let update = this[queryUpdateSymbol];
|
|
2258
|
+
if (update == null) {
|
|
2259
|
+
update = {};
|
|
2260
|
+
this[queryUpdateSymbol] = update;
|
|
2261
|
+
}
|
|
2262
|
+
if (path in update) {
|
|
2263
|
+
delete update[path];
|
|
2230
2264
|
}
|
|
2231
|
-
|
|
2232
|
-
|
|
2265
|
+
update.$set = update.$set || {};
|
|
2266
|
+
update.$set[path] = val;
|
|
2233
2267
|
return this;
|
|
2234
2268
|
};
|
|
2235
2269
|
|
|
@@ -2249,7 +2283,7 @@ Query.prototype.set = function(path, val) {
|
|
|
2249
2283
|
*/
|
|
2250
2284
|
|
|
2251
2285
|
Query.prototype.get = function get(path) {
|
|
2252
|
-
const update = this
|
|
2286
|
+
const update = this[queryUpdateSymbol];
|
|
2253
2287
|
if (update == null) {
|
|
2254
2288
|
return void 0;
|
|
2255
2289
|
}
|
|
@@ -2333,6 +2367,7 @@ Query.prototype._unsetCastError = function _unsetCastError() {
|
|
|
2333
2367
|
* - `strictQuery`: controls how Mongoose handles keys that aren't in the schema for the query `filter`. This option is `false` by default, which means Mongoose will allow `Model.find({ foo: 'bar' })` even if `foo` is not in the schema. See the [`strictQuery` docs](https://mongoosejs.com/docs/guide.html#strictQuery) for more information.
|
|
2334
2368
|
* - `nearSphere`: use `$nearSphere` instead of `near()`. See the [`Query.prototype.nearSphere()` docs](https://mongoosejs.com/docs/api/query.html#Query.prototype.nearSphere())
|
|
2335
2369
|
* - `schemaLevelProjections`: if `false`, Mongoose will not apply schema-level `select: false` or `select: true` for this query
|
|
2370
|
+
* - `cloneUpdate`: if `false`, Mongoose will not clone updates before executing the query
|
|
2336
2371
|
*
|
|
2337
2372
|
* Mongoose maintains a separate object for internal options because
|
|
2338
2373
|
* Mongoose sends `Query.prototype.options` to the MongoDB server, and the
|
|
@@ -2421,6 +2456,12 @@ Query.prototype._find = async function _find() {
|
|
|
2421
2456
|
lean: mongooseOptions.lean || null
|
|
2422
2457
|
};
|
|
2423
2458
|
|
|
2459
|
+
// Only pass `defaults` through when it is non-nullish; `null` and
|
|
2460
|
+
// `undefined` are treated as "not set" and omitted from `createModel()`.
|
|
2461
|
+
if (mongooseOptions.defaults != null) {
|
|
2462
|
+
completeManyOptions.defaults = mongooseOptions.defaults;
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2424
2465
|
const options = this._optionsForExec();
|
|
2425
2466
|
|
|
2426
2467
|
const filter = this._conditions;
|
|
@@ -2553,9 +2594,10 @@ Query.prototype.merge = function(source) {
|
|
|
2553
2594
|
utils.merge(this.options, source.options, opts);
|
|
2554
2595
|
}
|
|
2555
2596
|
|
|
2556
|
-
if (source
|
|
2557
|
-
|
|
2558
|
-
|
|
2597
|
+
if (source[queryUpdateSymbol] != null) {
|
|
2598
|
+
_cloneUpdateIfShared(this);
|
|
2599
|
+
this[queryUpdateSymbol] || (this[queryUpdateSymbol] = {});
|
|
2600
|
+
utils.mergeClone(this[queryUpdateSymbol], source[queryUpdateSymbol]);
|
|
2559
2601
|
}
|
|
2560
2602
|
|
|
2561
2603
|
if (source._distinct) {
|
|
@@ -2691,7 +2733,7 @@ Query.prototype._completeMany = async function _completeMany(docs, fields, userP
|
|
|
2691
2733
|
const model = this.model;
|
|
2692
2734
|
return Promise.all(docs.map(doc => new Promise((resolve, reject) => {
|
|
2693
2735
|
const rawDoc = doc;
|
|
2694
|
-
doc = helpers.createModel(model, doc, fields, userProvidedFields);
|
|
2736
|
+
doc = helpers.createModel(model, doc, fields, userProvidedFields, opts);
|
|
2695
2737
|
if (opts.session != null) {
|
|
2696
2738
|
doc.$session(opts.session);
|
|
2697
2739
|
}
|
|
@@ -2849,9 +2891,10 @@ Query.prototype._applyTranslateAliases = function _applyTranslateAliases() {
|
|
|
2849
2891
|
}
|
|
2850
2892
|
|
|
2851
2893
|
if (this.model?.schema?.aliases && utils.hasOwnKeys(this.model.schema.aliases)) {
|
|
2894
|
+
_cloneUpdateIfShared(this);
|
|
2852
2895
|
this.model.translateAliases(this._conditions, true);
|
|
2853
2896
|
this.model.translateAliases(this._fields, true);
|
|
2854
|
-
this.model.translateAliases(this
|
|
2897
|
+
this.model.translateAliases(this[queryUpdateSymbol], true);
|
|
2855
2898
|
if (this._distinct != null && this.model.schema.aliases[this._distinct] != null) {
|
|
2856
2899
|
this._distinct = this.model.schema.aliases[this._distinct];
|
|
2857
2900
|
}
|
|
@@ -3405,6 +3448,7 @@ function prepareDiscriminatorCriteria(query) {
|
|
|
3405
3448
|
* @param {object|Query} [filter]
|
|
3406
3449
|
* @param {object} [update]
|
|
3407
3450
|
* @param {object} [options]
|
|
3451
|
+
* @param {boolean} [options.cloneUpdate=true] if `false`, Mongoose will not clone the update before executing the query
|
|
3408
3452
|
* @param {boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/7.0/interfaces/ModifyResult.html) rather than just the document
|
|
3409
3453
|
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
3410
3454
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
@@ -3481,11 +3525,20 @@ Query.prototype.findOneAndUpdate = function(filter, update, options) {
|
|
|
3481
3525
|
options.updatePipeline = updatePipeline;
|
|
3482
3526
|
}
|
|
3483
3527
|
|
|
3528
|
+
if (!options.updatePipeline && Array.isArray(update)) {
|
|
3529
|
+
throw new MongooseError('Cannot pass an array to query updates unless the `updatePipeline` option is set.');
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3484
3532
|
this.setOptions(options);
|
|
3485
3533
|
|
|
3486
3534
|
// apply doc
|
|
3487
3535
|
if (update) {
|
|
3488
|
-
this.
|
|
3536
|
+
if (this[queryUpdateSymbol] == null || utils.isEmptyObject(this[queryUpdateSymbol])) {
|
|
3537
|
+
this[queryUpdateSymbol] = update;
|
|
3538
|
+
this._updateIsShared = true;
|
|
3539
|
+
} else {
|
|
3540
|
+
this._mergeUpdate(update);
|
|
3541
|
+
}
|
|
3489
3542
|
}
|
|
3490
3543
|
|
|
3491
3544
|
return this;
|
|
@@ -3523,49 +3576,51 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
|
|
|
3523
3576
|
const options = this._optionsForExec(this.model);
|
|
3524
3577
|
convertNewToReturnDocument(options);
|
|
3525
3578
|
|
|
3526
|
-
this
|
|
3579
|
+
this[queryUpdateSymbol] = this._castUpdate(this[queryUpdateSymbol]);
|
|
3580
|
+
this._updateIsShared = false;
|
|
3581
|
+
decorateUpdateWithVersionKey(this[queryUpdateSymbol], options, this.schema.options.versionKey);
|
|
3527
3582
|
|
|
3528
|
-
this
|
|
3583
|
+
this[queryUpdateSymbol] = setDefaultsOnInsert(
|
|
3529
3584
|
this._conditions,
|
|
3530
3585
|
this.model.schema,
|
|
3531
|
-
this
|
|
3586
|
+
this[queryUpdateSymbol],
|
|
3532
3587
|
options,
|
|
3533
3588
|
this._mongooseOptions,
|
|
3534
3589
|
this
|
|
3535
3590
|
);
|
|
3536
3591
|
|
|
3537
|
-
if (!this
|
|
3592
|
+
if (!this[queryUpdateSymbol] || utils.hasOwnKeys(this[queryUpdateSymbol]) === false) {
|
|
3538
3593
|
if (options.upsert) {
|
|
3539
3594
|
// still need to do the upsert to empty doc
|
|
3540
|
-
const $set = clone(this
|
|
3595
|
+
const $set = clone(this[queryUpdateSymbol]);
|
|
3541
3596
|
delete $set._id;
|
|
3542
|
-
this
|
|
3597
|
+
this[queryUpdateSymbol] = { $set };
|
|
3543
3598
|
} else {
|
|
3544
3599
|
this._execCount = 0;
|
|
3545
3600
|
const res = await this._findOne();
|
|
3546
3601
|
return res;
|
|
3547
3602
|
}
|
|
3548
|
-
} else if (this
|
|
3549
|
-
throw this
|
|
3603
|
+
} else if (this[queryUpdateSymbol] instanceof Error) {
|
|
3604
|
+
throw this[queryUpdateSymbol];
|
|
3550
3605
|
} else {
|
|
3551
3606
|
// In order to make MongoDB 2.6 happy (see
|
|
3552
3607
|
// https://jira.mongodb.org/browse/SERVER-12266 and related issues)
|
|
3553
3608
|
// if we have an actual update document but $set is empty, junk the $set.
|
|
3554
|
-
if (this
|
|
3555
|
-
delete this
|
|
3609
|
+
if (this[queryUpdateSymbol].$set && utils.hasOwnKeys(this[queryUpdateSymbol].$set) === false) {
|
|
3610
|
+
delete this[queryUpdateSymbol].$set;
|
|
3556
3611
|
}
|
|
3557
3612
|
}
|
|
3558
3613
|
|
|
3559
3614
|
const runValidators = _getOption(this, 'runValidators', false);
|
|
3560
3615
|
if (runValidators) {
|
|
3561
|
-
await this.validate(this
|
|
3616
|
+
await this.validate(this[queryUpdateSymbol], options, false);
|
|
3562
3617
|
}
|
|
3563
3618
|
|
|
3564
|
-
if (typeof this.
|
|
3565
|
-
this
|
|
3619
|
+
if (typeof this[queryUpdateSymbol].toBSON === 'function') {
|
|
3620
|
+
this[queryUpdateSymbol] = this[queryUpdateSymbol].toBSON();
|
|
3566
3621
|
}
|
|
3567
3622
|
|
|
3568
|
-
let res = await this.mongooseCollection.findOneAndUpdate(this._conditions, this
|
|
3623
|
+
let res = await this.mongooseCollection.findOneAndUpdate(this._conditions, this[queryUpdateSymbol], options);
|
|
3569
3624
|
for (const fn of this._transforms) {
|
|
3570
3625
|
res = fn(res);
|
|
3571
3626
|
}
|
|
@@ -3701,6 +3756,7 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() {
|
|
|
3701
3756
|
* @param {object} [filter]
|
|
3702
3757
|
* @param {object} [replacement]
|
|
3703
3758
|
* @param {object} [options]
|
|
3759
|
+
* @param {boolean} [options.cloneUpdate=true] if `false`, Mongoose will not clone the update before executing the query
|
|
3704
3760
|
* @param {boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/7.0/interfaces/ModifyResult.html) rather than just the document
|
|
3705
3761
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
3706
3762
|
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
@@ -3796,13 +3852,13 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() {
|
|
|
3796
3852
|
const runValidators = _getOption(this, 'runValidators', false);
|
|
3797
3853
|
|
|
3798
3854
|
try {
|
|
3799
|
-
const update = new this.model(this
|
|
3855
|
+
const update = new this.model(this[queryUpdateSymbol], null, modelOpts);
|
|
3800
3856
|
if (runValidators) {
|
|
3801
3857
|
await update.validate();
|
|
3802
3858
|
} else if (update.$__.validationError) {
|
|
3803
3859
|
throw update.$__.validationError;
|
|
3804
3860
|
}
|
|
3805
|
-
this
|
|
3861
|
+
this[queryUpdateSymbol] = update.toBSON();
|
|
3806
3862
|
} catch (err) {
|
|
3807
3863
|
if (err instanceof ValidationError) {
|
|
3808
3864
|
throw err;
|
|
@@ -3812,7 +3868,7 @@ Query.prototype._findOneAndReplace = async function _findOneAndReplace() {
|
|
|
3812
3868
|
throw validationError;
|
|
3813
3869
|
}
|
|
3814
3870
|
|
|
3815
|
-
let res = await this.mongooseCollection.findOneAndReplace(filter, this
|
|
3871
|
+
let res = await this.mongooseCollection.findOneAndReplace(filter, this[queryUpdateSymbol], options);
|
|
3816
3872
|
|
|
3817
3873
|
for (const fn of this._transforms) {
|
|
3818
3874
|
res = fn(res);
|
|
@@ -3874,6 +3930,7 @@ Query.prototype.findById = function(id, projection, options) {
|
|
|
3874
3930
|
* @param {any} id value of `_id` to query by
|
|
3875
3931
|
* @param {object} [doc]
|
|
3876
3932
|
* @param {object} [options]
|
|
3933
|
+
* @param {boolean} [options.cloneUpdate=true] if `false`, Mongoose will not clone the update before executing the query
|
|
3877
3934
|
* @param {boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/7.0/interfaces/ModifyResult.html) rather than just the document
|
|
3878
3935
|
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
3879
3936
|
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
|
|
@@ -4049,12 +4106,14 @@ function _completeManyLean(schema, docs, path, opts) {
|
|
|
4049
4106
|
*/
|
|
4050
4107
|
|
|
4051
4108
|
Query.prototype._mergeUpdate = function(update) {
|
|
4109
|
+
_cloneUpdateIfShared(this);
|
|
4110
|
+
|
|
4052
4111
|
const updatePipeline = this._mongooseOptions.updatePipeline;
|
|
4053
4112
|
if (!updatePipeline && Array.isArray(update)) {
|
|
4054
4113
|
throw new MongooseError('Cannot pass an array to query updates unless the `updatePipeline` option is set.');
|
|
4055
4114
|
}
|
|
4056
|
-
if (!this
|
|
4057
|
-
this
|
|
4115
|
+
if (!this[queryUpdateSymbol]) {
|
|
4116
|
+
this[queryUpdateSymbol] = Array.isArray(update) ? [] : {};
|
|
4058
4117
|
}
|
|
4059
4118
|
|
|
4060
4119
|
if (update == null || (typeof update === 'object' && utils.hasOwnKeys(update) === false)) {
|
|
@@ -4062,28 +4121,28 @@ Query.prototype._mergeUpdate = function(update) {
|
|
|
4062
4121
|
}
|
|
4063
4122
|
|
|
4064
4123
|
if (update instanceof Query) {
|
|
4065
|
-
if (Array.isArray(this
|
|
4066
|
-
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this
|
|
4124
|
+
if (Array.isArray(this[queryUpdateSymbol])) {
|
|
4125
|
+
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update[queryUpdateSymbol])})`);
|
|
4067
4126
|
}
|
|
4068
|
-
if (update
|
|
4069
|
-
utils.mergeClone(this
|
|
4127
|
+
if (update[queryUpdateSymbol]) {
|
|
4128
|
+
utils.mergeClone(this[queryUpdateSymbol], update[queryUpdateSymbol]);
|
|
4070
4129
|
}
|
|
4071
4130
|
} else if (Array.isArray(update)) {
|
|
4072
|
-
if (!Array.isArray(this
|
|
4131
|
+
if (!Array.isArray(this[queryUpdateSymbol])) {
|
|
4073
4132
|
// `_update` may be empty object by default, like in `doc.updateOne()`
|
|
4074
4133
|
// because we create the query first, then run hooks, then apply the update.
|
|
4075
|
-
if (this
|
|
4076
|
-
this
|
|
4134
|
+
if (this[queryUpdateSymbol] == null || utils.isEmptyObject(this[queryUpdateSymbol])) {
|
|
4135
|
+
this[queryUpdateSymbol] = [];
|
|
4077
4136
|
} else {
|
|
4078
|
-
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this
|
|
4137
|
+
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update)})`);
|
|
4079
4138
|
}
|
|
4080
4139
|
}
|
|
4081
|
-
this
|
|
4140
|
+
this[queryUpdateSymbol] = this[queryUpdateSymbol].concat(update);
|
|
4082
4141
|
} else {
|
|
4083
|
-
if (Array.isArray(this
|
|
4084
|
-
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this
|
|
4142
|
+
if (Array.isArray(this[queryUpdateSymbol])) {
|
|
4143
|
+
throw new MongooseError(`Cannot mix array and object updates (current: ${_previewUpdate(this[queryUpdateSymbol])}, incoming: ${_previewUpdate(update)})`);
|
|
4085
4144
|
}
|
|
4086
|
-
utils.mergeClone(this
|
|
4145
|
+
utils.mergeClone(this[queryUpdateSymbol], update);
|
|
4087
4146
|
}
|
|
4088
4147
|
};
|
|
4089
4148
|
|
|
@@ -4157,30 +4216,31 @@ Query.prototype._updateMany = async function _updateMany() {
|
|
|
4157
4216
|
}
|
|
4158
4217
|
|
|
4159
4218
|
const options = this._optionsForExec(this.model);
|
|
4160
|
-
|
|
4161
|
-
|
|
4219
|
+
_cloneUpdateIfShared(this);
|
|
4220
|
+
this[queryUpdateSymbol] = this._castUpdate(this[queryUpdateSymbol]);
|
|
4221
|
+
if (this[queryUpdateSymbol] == null || utils.hasOwnKeys(this[queryUpdateSymbol]) === false) {
|
|
4162
4222
|
return { acknowledged: false };
|
|
4163
4223
|
}
|
|
4164
|
-
removeUnusedArrayFilters(this
|
|
4224
|
+
removeUnusedArrayFilters(this[queryUpdateSymbol], options);
|
|
4165
4225
|
|
|
4166
|
-
this
|
|
4226
|
+
this[queryUpdateSymbol] = setDefaultsOnInsert(
|
|
4167
4227
|
this._conditions,
|
|
4168
4228
|
this.model.schema,
|
|
4169
|
-
this
|
|
4229
|
+
this[queryUpdateSymbol],
|
|
4170
4230
|
options,
|
|
4171
4231
|
this._mongooseOptions,
|
|
4172
4232
|
this
|
|
4173
4233
|
);
|
|
4174
4234
|
|
|
4175
4235
|
if (_getOption(this, 'runValidators', false)) {
|
|
4176
|
-
await this.validate(this
|
|
4236
|
+
await this.validate(this[queryUpdateSymbol], options, false);
|
|
4177
4237
|
}
|
|
4178
4238
|
|
|
4179
|
-
if (typeof this.
|
|
4180
|
-
this
|
|
4239
|
+
if (typeof this[queryUpdateSymbol].toBSON === 'function') {
|
|
4240
|
+
this[queryUpdateSymbol] = this[queryUpdateSymbol].toBSON();
|
|
4181
4241
|
}
|
|
4182
4242
|
|
|
4183
|
-
return this.mongooseCollection.updateMany(this._conditions, this
|
|
4243
|
+
return this.mongooseCollection.updateMany(this._conditions, this[queryUpdateSymbol], options);
|
|
4184
4244
|
};
|
|
4185
4245
|
|
|
4186
4246
|
/**
|
|
@@ -4202,30 +4262,31 @@ Query.prototype._updateOne = async function _updateOne() {
|
|
|
4202
4262
|
}
|
|
4203
4263
|
|
|
4204
4264
|
const options = this._optionsForExec(this.model);
|
|
4205
|
-
|
|
4206
|
-
|
|
4265
|
+
_cloneUpdateIfShared(this);
|
|
4266
|
+
this[queryUpdateSymbol] = this._castUpdate(this[queryUpdateSymbol]);
|
|
4267
|
+
if (this[queryUpdateSymbol] == null || utils.hasOwnKeys(this[queryUpdateSymbol]) === false) {
|
|
4207
4268
|
return { acknowledged: false };
|
|
4208
4269
|
}
|
|
4209
|
-
removeUnusedArrayFilters(this
|
|
4270
|
+
removeUnusedArrayFilters(this[queryUpdateSymbol], options);
|
|
4210
4271
|
|
|
4211
|
-
this
|
|
4272
|
+
this[queryUpdateSymbol] = setDefaultsOnInsert(
|
|
4212
4273
|
this._conditions,
|
|
4213
4274
|
this.model.schema,
|
|
4214
|
-
this
|
|
4275
|
+
this[queryUpdateSymbol],
|
|
4215
4276
|
options,
|
|
4216
4277
|
this._mongooseOptions,
|
|
4217
4278
|
this
|
|
4218
4279
|
);
|
|
4219
4280
|
|
|
4220
4281
|
if (_getOption(this, 'runValidators', false)) {
|
|
4221
|
-
await this.validate(this
|
|
4282
|
+
await this.validate(this[queryUpdateSymbol], options, false);
|
|
4222
4283
|
}
|
|
4223
4284
|
|
|
4224
|
-
if (typeof this.
|
|
4225
|
-
this
|
|
4285
|
+
if (typeof this[queryUpdateSymbol].toBSON === 'function') {
|
|
4286
|
+
this[queryUpdateSymbol] = this[queryUpdateSymbol].toBSON();
|
|
4226
4287
|
}
|
|
4227
4288
|
|
|
4228
|
-
return this.mongooseCollection.updateOne(this._conditions, this
|
|
4289
|
+
return this.mongooseCollection.updateOne(this._conditions, this[queryUpdateSymbol], options);
|
|
4229
4290
|
};
|
|
4230
4291
|
|
|
4231
4292
|
/**
|
|
@@ -4247,18 +4308,18 @@ Query.prototype._replaceOne = async function _replaceOne() {
|
|
|
4247
4308
|
}
|
|
4248
4309
|
|
|
4249
4310
|
const options = this._optionsForExec(this.model);
|
|
4250
|
-
this
|
|
4251
|
-
removeUnusedArrayFilters(this
|
|
4311
|
+
this[queryUpdateSymbol] = new this.model(this[queryUpdateSymbol], null, { skipId: true });
|
|
4312
|
+
removeUnusedArrayFilters(this[queryUpdateSymbol], options);
|
|
4252
4313
|
|
|
4253
4314
|
if (_getOption(this, 'runValidators', false)) {
|
|
4254
|
-
await this.validate(this
|
|
4315
|
+
await this.validate(this[queryUpdateSymbol], options, true);
|
|
4255
4316
|
}
|
|
4256
4317
|
|
|
4257
|
-
if (typeof this.
|
|
4258
|
-
this
|
|
4318
|
+
if (typeof this[queryUpdateSymbol].toBSON === 'function') {
|
|
4319
|
+
this[queryUpdateSymbol] = this[queryUpdateSymbol].toBSON();
|
|
4259
4320
|
}
|
|
4260
4321
|
|
|
4261
|
-
return this.mongooseCollection.replaceOne(this._conditions, this
|
|
4322
|
+
return this.mongooseCollection.replaceOne(this._conditions, this[queryUpdateSymbol], options);
|
|
4262
4323
|
};
|
|
4263
4324
|
|
|
4264
4325
|
/**
|
|
@@ -4285,6 +4346,7 @@ Query.prototype._replaceOne = async function _replaceOne() {
|
|
|
4285
4346
|
* @param {object} [filter]
|
|
4286
4347
|
* @param {object|Array} [update] the update command. If array, this update will be treated as an update pipeline and not casted.
|
|
4287
4348
|
* @param {object} [options]
|
|
4349
|
+
* @param {boolean} [options.cloneUpdate=true] if `false`, Mongoose will not clone the update before executing the query
|
|
4288
4350
|
* @param {boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
|
|
4289
4351
|
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
4290
4352
|
* @param {boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
@@ -4360,6 +4422,7 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
|
|
|
4360
4422
|
* @param {object} [filter]
|
|
4361
4423
|
* @param {object|Array} [update] the update command. If array, this update will be treated as an update pipeline and not casted.
|
|
4362
4424
|
* @param {object} [options]
|
|
4425
|
+
* @param {boolean} [options.cloneUpdate=true] if `false`, Mongoose will not clone the update before executing the query
|
|
4363
4426
|
* @param {boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
|
|
4364
4427
|
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
4365
4428
|
* @param {boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
@@ -4429,6 +4492,7 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) {
|
|
|
4429
4492
|
* @param {object} [filter]
|
|
4430
4493
|
* @param {object} [doc] the update command
|
|
4431
4494
|
* @param {object} [options]
|
|
4495
|
+
* @param {boolean} [options.cloneUpdate=true] if `false`, Mongoose will not clone the update before executing the query
|
|
4432
4496
|
* @param {boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
|
|
4433
4497
|
* @param {boolean|'throw'} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
4434
4498
|
* @param {boolean} [options.upsert=false] if true, and no documents found, insert a new document
|
|
@@ -4510,11 +4574,20 @@ function _update(query, op, filter, doc, options, callback) {
|
|
|
4510
4574
|
options.updatePipeline = updatePipeline;
|
|
4511
4575
|
}
|
|
4512
4576
|
|
|
4577
|
+
if (!options?.updatePipeline && Array.isArray(doc)) {
|
|
4578
|
+
throw new MongooseError('Cannot pass an array to query updates unless the `updatePipeline` option is set.');
|
|
4579
|
+
}
|
|
4580
|
+
|
|
4513
4581
|
if (utils.isObject(options)) {
|
|
4514
4582
|
query.setOptions(options);
|
|
4515
4583
|
}
|
|
4516
4584
|
|
|
4517
|
-
query.
|
|
4585
|
+
if (query[queryUpdateSymbol] == null || utils.isEmptyObject(query[queryUpdateSymbol])) {
|
|
4586
|
+
query[queryUpdateSymbol] = doc;
|
|
4587
|
+
query._updateIsShared = true;
|
|
4588
|
+
} else {
|
|
4589
|
+
query._mergeUpdate(doc);
|
|
4590
|
+
}
|
|
4518
4591
|
|
|
4519
4592
|
// Hooks
|
|
4520
4593
|
if (callback) {
|
|
@@ -4707,42 +4780,56 @@ Query.prototype.exec = async function exec(op) {
|
|
|
4707
4780
|
}
|
|
4708
4781
|
this._execCount++;
|
|
4709
4782
|
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4783
|
+
const _this = this;
|
|
4784
|
+
return traceQuery(async function maybeTracedQueryExec() {
|
|
4785
|
+
let skipWrappedFunction = null;
|
|
4786
|
+
try {
|
|
4787
|
+
await _this._hooks.execPre('exec', _this, []);
|
|
4788
|
+
} catch (err) {
|
|
4789
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
4790
|
+
skipWrappedFunction = err;
|
|
4791
|
+
} else {
|
|
4792
|
+
throw err;
|
|
4793
|
+
}
|
|
4718
4794
|
}
|
|
4719
|
-
}
|
|
4720
4795
|
|
|
4721
|
-
|
|
4796
|
+
let res;
|
|
4722
4797
|
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4798
|
+
let error = null;
|
|
4799
|
+
try {
|
|
4800
|
+
await _executePreHooks(_this);
|
|
4801
|
+
res = skipWrappedFunction ? skipWrappedFunction.args[0] : await _this[thunk]();
|
|
4727
4802
|
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4803
|
+
for (const fn of _this._transforms) {
|
|
4804
|
+
res = fn(res);
|
|
4805
|
+
}
|
|
4806
|
+
} catch (err) {
|
|
4807
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
4808
|
+
res = err.args[0];
|
|
4809
|
+
} else {
|
|
4810
|
+
error = err;
|
|
4811
|
+
}
|
|
4737
4812
|
|
|
4738
|
-
|
|
4739
|
-
|
|
4813
|
+
error = _this.model.schema._transformDuplicateKeyError(error);
|
|
4814
|
+
}
|
|
4740
4815
|
|
|
4741
|
-
|
|
4816
|
+
res = await _executePostHooks(_this, res, error);
|
|
4742
4817
|
|
|
4743
|
-
|
|
4818
|
+
await _this._hooks.execPost('exec', _this, []);
|
|
4744
4819
|
|
|
4745
|
-
|
|
4820
|
+
return res;
|
|
4821
|
+
}, () => ({
|
|
4822
|
+
operation: _this.op,
|
|
4823
|
+
collection: _this.mongooseCollection.name,
|
|
4824
|
+
database: _this.model.db?.name,
|
|
4825
|
+
serverAddress: _this.model.db?.host,
|
|
4826
|
+
serverPort: _this.model.db?.port,
|
|
4827
|
+
args: {
|
|
4828
|
+
filter: _this.getFilter(),
|
|
4829
|
+
fields: _this._fields,
|
|
4830
|
+
options: _this._mongooseOptions
|
|
4831
|
+
}
|
|
4832
|
+
}));
|
|
4746
4833
|
};
|
|
4747
4834
|
|
|
4748
4835
|
/*!
|
|
@@ -4789,6 +4876,20 @@ function _executePreHooks(query, op) {
|
|
|
4789
4876
|
);
|
|
4790
4877
|
}
|
|
4791
4878
|
|
|
4879
|
+
function _cloneUpdateIfShared(query) {
|
|
4880
|
+
if (!query._updateIsShared) {
|
|
4881
|
+
return;
|
|
4882
|
+
}
|
|
4883
|
+
if (query.mongooseOptions().cloneUpdate === false) {
|
|
4884
|
+
return;
|
|
4885
|
+
}
|
|
4886
|
+
|
|
4887
|
+
query[queryUpdateSymbol] = clone(query[queryUpdateSymbol], {
|
|
4888
|
+
flattenDecimals: false
|
|
4889
|
+
});
|
|
4890
|
+
query._updateIsShared = false;
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4792
4893
|
/**
|
|
4793
4894
|
* Executes the query returning a `Promise` which will be
|
|
4794
4895
|
* resolved with either the doc(s) or rejected with the error.
|
|
@@ -4987,12 +5088,17 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
|
|
|
4987
5088
|
* @param {object} [match] Conditions for the population query
|
|
4988
5089
|
* @param {object} [options] Options for the population query (sort, etc)
|
|
4989
5090
|
* @param {string} [options.path=null] The path to populate.
|
|
5091
|
+
* @param {string|PopulateOptions} [options.populate=null] Recursively populate paths in the populated documents. See [deep populate docs](https://mongoosejs.com/docs/populate.html#deep-populate).
|
|
4990
5092
|
* @param {boolean} [options.retainNullValues=false] by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
|
|
4991
5093
|
* @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](https://mongoosejs.com/docs/schematypes.html#schematype-options).
|
|
4992
5094
|
* @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
|
|
4993
5095
|
* @param {object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
|
|
5096
|
+
* @param {boolean} [options.skipInvalidIds=false] By default, Mongoose throws a cast error if `localField` and `foreignField` schemas don't line up. If you enable this option, Mongoose will instead filter out any `localField` properties that cannot be casted to `foreignField`'s schema type.
|
|
5097
|
+
* @param {number} [options.perDocumentLimit=null] For legacy reasons, `limit` with `populate()` may give incorrect results because it only executes a single query for every document being populated. If you set `perDocumentLimit`, Mongoose will ensure correct `limit` per document by executing a separate query for each document to `populate()`. For example, `.find().populate({ path: 'test', perDocumentLimit: 2 })` will execute 2 additional queries if `.find()` returns 2 documents.
|
|
5098
|
+
* @param {boolean} [options.strictPopulate=true] Set to false to allow populating paths that aren't defined in the given model's schema.
|
|
4994
5099
|
* @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
|
|
4995
5100
|
* @param {object} [options.options=null] Additional options like `limit` and `lean`.
|
|
5101
|
+
* @param {boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. Set this option to `true` if populating multiple paths or paths with multiple models in transactions.
|
|
4996
5102
|
* @see population https://mongoosejs.com/docs/populate.html
|
|
4997
5103
|
* @see Query#select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()
|
|
4998
5104
|
* @see Model.populate https://mongoosejs.com/docs/api/model.html#Model.populate()
|