mongoose 6.2.1 → 6.2.4
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/.eslintrc.json +5 -1
- package/.lgtm.yml +3 -0
- package/CHANGELOG.md +54 -0
- package/dist/browser.umd.js +156 -152
- package/index.js +5 -1
- package/lib/aggregate.js +22 -27
- package/lib/browserDocument.js +1 -1
- package/lib/cast/number.js +2 -3
- package/lib/cast.js +7 -4
- package/lib/connection.js +43 -21
- package/lib/cursor/AggregationCursor.js +12 -7
- package/lib/cursor/QueryCursor.js +11 -6
- package/lib/document.js +58 -72
- package/lib/drivers/node-mongodb-native/collection.js +12 -4
- package/lib/drivers/node-mongodb-native/connection.js +11 -0
- package/lib/error/cast.js +3 -2
- package/lib/helpers/clone.js +11 -2
- package/lib/helpers/cursor/eachAsync.js +18 -15
- package/lib/helpers/document/cleanModifiedSubpaths.js +1 -0
- package/lib/helpers/document/compile.js +7 -4
- package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
- package/lib/helpers/indexes/getRelatedIndexes.js +59 -0
- package/lib/helpers/isAsyncFunction.js +6 -7
- package/lib/helpers/populate/assignVals.js +4 -0
- package/lib/helpers/printJestWarning.js +2 -2
- package/lib/helpers/projection/applyProjection.js +77 -0
- package/lib/helpers/projection/hasIncludedChildren.js +36 -0
- package/lib/helpers/projection/isExclusive.js +5 -2
- package/lib/helpers/projection/isInclusive.js +5 -1
- package/lib/helpers/query/cast$expr.js +14 -19
- package/lib/helpers/query/hasDollarKeys.js +7 -3
- package/lib/helpers/query/isOperator.js +5 -2
- package/lib/helpers/schema/getIndexes.js +6 -2
- package/lib/index.js +14 -17
- package/lib/internal.js +9 -1
- package/lib/model.js +159 -153
- package/lib/options/SchemaTypeOptions.js +1 -1
- package/lib/plugins/trackTransaction.js +1 -1
- package/lib/query.js +159 -147
- package/lib/queryhelpers.js +8 -28
- package/lib/schema/SubdocumentPath.js +5 -4
- package/lib/schema/array.js +13 -6
- package/lib/schema/buffer.js +1 -1
- package/lib/schema/date.js +1 -1
- package/lib/schema/decimal128.js +1 -1
- package/lib/schema/documentarray.js +9 -7
- package/lib/schema/number.js +1 -1
- package/lib/schema/objectid.js +1 -1
- package/lib/schema/string.js +4 -4
- package/lib/schema.js +12 -8
- package/lib/schematype.js +12 -14
- package/lib/types/ArraySubdocument.js +1 -1
- package/lib/types/DocumentArray/index.js +1 -1
- package/lib/types/array/index.js +2 -2
- package/lib/types/array/methods/index.js +10 -11
- package/lib/types/buffer.js +3 -3
- package/lib/types/map.js +3 -4
- package/lib/utils.js +9 -3
- package/package.json +17 -21
- package/tsconfig.json +0 -2
- package/types/Connection.d.ts +212 -0
- package/types/Error.d.ts +129 -0
- package/types/PipelineStage.d.ts +272 -0
- package/types/index.d.ts +61 -602
- package/lib/types/array/ArrayWrapper.js +0 -981
package/lib/document.js
CHANGED
|
@@ -16,6 +16,7 @@ const StrictModeError = require('./error/strict');
|
|
|
16
16
|
const ValidationError = require('./error/validation');
|
|
17
17
|
const ValidatorError = require('./error/validator');
|
|
18
18
|
const VirtualType = require('./virtualtype');
|
|
19
|
+
const $__hasIncludedChildren = require('./helpers/projection/hasIncludedChildren');
|
|
19
20
|
const promiseOrCallback = require('./helpers/promiseOrCallback');
|
|
20
21
|
const cleanModifiedSubpaths = require('./helpers/document/cleanModifiedSubpaths');
|
|
21
22
|
const compile = require('./helpers/document/compile').compile;
|
|
@@ -66,7 +67,7 @@ const specialProperties = utils.specialProperties;
|
|
|
66
67
|
* @param {Object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
|
|
67
68
|
* @param {Object} [options] various configuration options for the document
|
|
68
69
|
* @param {Boolean} [options.defaults=true] if `false`, skip applying default values to this document.
|
|
69
|
-
* @inherits NodeJS EventEmitter
|
|
70
|
+
* @inherits NodeJS EventEmitter https://nodejs.org/api/events.html#events_class_events_eventemitter
|
|
70
71
|
* @event `init`: Emitted on a document after it has been retrieved from the db and fully hydrated by Mongoose.
|
|
71
72
|
* @event `save`: Emitted when the document is successfully saved
|
|
72
73
|
* @api private
|
|
@@ -96,6 +97,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
96
97
|
if ('priorDoc' in options) {
|
|
97
98
|
this.$__.priorDoc = options.priorDoc;
|
|
98
99
|
}
|
|
100
|
+
|
|
99
101
|
if (skipId) {
|
|
100
102
|
this.$__.skipId = skipId;
|
|
101
103
|
}
|
|
@@ -140,7 +142,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
140
142
|
|
|
141
143
|
const hasIncludedChildren = exclude === false && fields ?
|
|
142
144
|
$__hasIncludedChildren(fields) :
|
|
143
|
-
|
|
145
|
+
null;
|
|
144
146
|
|
|
145
147
|
if (this._doc == null) {
|
|
146
148
|
this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren, false);
|
|
@@ -148,9 +150,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
148
150
|
// By default, defaults get applied **before** setting initial values
|
|
149
151
|
// Re: gh-6155
|
|
150
152
|
if (defaults) {
|
|
151
|
-
$__applyDefaults(this, fields, exclude, hasIncludedChildren, true,
|
|
152
|
-
isNew: this.$isNew
|
|
153
|
-
});
|
|
153
|
+
$__applyDefaults(this, fields, exclude, hasIncludedChildren, true, null);
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
if (obj) {
|
|
@@ -174,9 +174,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
174
174
|
this.$__.skipDefaults = options.skipDefaults;
|
|
175
175
|
}
|
|
176
176
|
} else if (defaults) {
|
|
177
|
-
$__applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults
|
|
178
|
-
isNew: this.$isNew
|
|
179
|
-
});
|
|
177
|
+
$__applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults);
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
this.$__._id = this._id;
|
|
@@ -417,33 +415,6 @@ Object.defineProperty(Document.prototype, '$op', {
|
|
|
417
415
|
}
|
|
418
416
|
});
|
|
419
417
|
|
|
420
|
-
/*!
|
|
421
|
-
* ignore
|
|
422
|
-
*/
|
|
423
|
-
|
|
424
|
-
function $__hasIncludedChildren(fields) {
|
|
425
|
-
const hasIncludedChildren = {};
|
|
426
|
-
const keys = Object.keys(fields);
|
|
427
|
-
|
|
428
|
-
for (const key of keys) {
|
|
429
|
-
if (key.indexOf('.') === -1) {
|
|
430
|
-
hasIncludedChildren[key] = 1;
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
const parts = key.split('.');
|
|
434
|
-
let c = parts[0];
|
|
435
|
-
|
|
436
|
-
for (let i = 0; i < parts.length; ++i) {
|
|
437
|
-
hasIncludedChildren[c] = 1;
|
|
438
|
-
if (i + 1 < parts.length) {
|
|
439
|
-
c = c + '.' + parts[i + 1];
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return hasIncludedChildren;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
418
|
/*!
|
|
448
419
|
* ignore
|
|
449
420
|
*/
|
|
@@ -479,9 +450,10 @@ function $__applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSet
|
|
|
479
450
|
break;
|
|
480
451
|
}
|
|
481
452
|
} else if (exclude === false && fields && !included) {
|
|
482
|
-
|
|
453
|
+
const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray;
|
|
454
|
+
if (curPath in fields || (hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) {
|
|
483
455
|
included = true;
|
|
484
|
-
} else if (!hasIncludedChildren[curPath]) {
|
|
456
|
+
} else if (hasIncludedChildren != null && !hasIncludedChildren[curPath]) {
|
|
485
457
|
break;
|
|
486
458
|
}
|
|
487
459
|
}
|
|
@@ -775,7 +747,7 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
775
747
|
|
|
776
748
|
const hasIncludedChildren = this.$__.exclude === false && this.$__.fields ?
|
|
777
749
|
$__hasIncludedChildren(this.$__.fields) :
|
|
778
|
-
|
|
750
|
+
null;
|
|
779
751
|
$__applyDefaults(this, this.$__.fields, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);
|
|
780
752
|
|
|
781
753
|
return this;
|
|
@@ -914,9 +886,9 @@ Document.prototype.update = function update() {
|
|
|
914
886
|
*
|
|
915
887
|
* @see Model.updateOne #model_Model.updateOne
|
|
916
888
|
* @param {Object} doc
|
|
917
|
-
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](
|
|
889
|
+
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api.html#query_Query-setOptions)
|
|
918
890
|
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](/docs/api.html#query_Query-lean) and the [Mongoose lean tutorial](/docs/tutorials/lean.html).
|
|
919
|
-
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](
|
|
891
|
+
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
920
892
|
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](/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.
|
|
921
893
|
* @param {Function} callback
|
|
922
894
|
* @return {Query}
|
|
@@ -1119,7 +1091,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1119
1091
|
|
|
1120
1092
|
// `_skipMinimizeTopLevel` is because we may have deleted the top-level
|
|
1121
1093
|
// nested key to ensure key order.
|
|
1122
|
-
const _skipMinimizeTopLevel =
|
|
1094
|
+
const _skipMinimizeTopLevel = options._skipMinimizeTopLevel || false;
|
|
1123
1095
|
if (len === 0 && _skipMinimizeTopLevel) {
|
|
1124
1096
|
delete options._skipMinimizeTopLevel;
|
|
1125
1097
|
if (val) {
|
|
@@ -1252,7 +1224,6 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1252
1224
|
} else {
|
|
1253
1225
|
this.markModified(path);
|
|
1254
1226
|
}
|
|
1255
|
-
cleanModifiedSubpaths(this, path, { skipDocArrays: true });
|
|
1256
1227
|
return this;
|
|
1257
1228
|
}
|
|
1258
1229
|
this.invalidate(path, new MongooseError.CastError('Object', val, path));
|
|
@@ -1263,7 +1234,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1263
1234
|
const parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
1264
1235
|
|
|
1265
1236
|
// Might need to change path for top-level alias
|
|
1266
|
-
if (typeof this.$__schema.aliases[parts[0]]
|
|
1237
|
+
if (typeof this.$__schema.aliases[parts[0]] === 'string') {
|
|
1267
1238
|
parts[0] = this.$__schema.aliases[parts[0]];
|
|
1268
1239
|
}
|
|
1269
1240
|
|
|
@@ -1407,8 +1378,9 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1407
1378
|
|
|
1408
1379
|
let didPopulate = false;
|
|
1409
1380
|
if (refMatches && val instanceof Document) {
|
|
1410
|
-
|
|
1411
|
-
val
|
|
1381
|
+
const unpopulatedValue = (schema && schema.$isSingleNested) ? schema.cast(val, this) : val._id;
|
|
1382
|
+
this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
|
|
1383
|
+
val.$__.wasPopulated = { value: unpopulatedValue };
|
|
1412
1384
|
didPopulate = true;
|
|
1413
1385
|
}
|
|
1414
1386
|
|
|
@@ -1422,7 +1394,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1422
1394
|
this.$populated(path, val.map(function(v) { return v._id; }), popOpts);
|
|
1423
1395
|
|
|
1424
1396
|
for (const doc of val) {
|
|
1425
|
-
doc.$__.wasPopulated =
|
|
1397
|
+
doc.$__.wasPopulated = { value: doc._id };
|
|
1426
1398
|
}
|
|
1427
1399
|
didPopulate = true;
|
|
1428
1400
|
}
|
|
@@ -1787,7 +1759,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1787
1759
|
}
|
|
1788
1760
|
|
|
1789
1761
|
// Might need to change path for top-level alias
|
|
1790
|
-
if (typeof this.$__schema.aliases[pieces[0]]
|
|
1762
|
+
if (typeof this.$__schema.aliases[pieces[0]] === 'string') {
|
|
1791
1763
|
pieces[0] = this.$__schema.aliases[pieces[0]];
|
|
1792
1764
|
}
|
|
1793
1765
|
|
|
@@ -2539,7 +2511,9 @@ function _getPathsToValidate(doc) {
|
|
|
2539
2511
|
// To avoid potential performance issues, skip doc arrays whose children
|
|
2540
2512
|
// are not required. `getPositionalPathType()` may be slow, so avoid
|
|
2541
2513
|
// it unless we have a case of #6364
|
|
2542
|
-
(!Array.isArray(_pathType) &&
|
|
2514
|
+
(!Array.isArray(_pathType) &&
|
|
2515
|
+
_pathType.$isMongooseDocumentArray &&
|
|
2516
|
+
!(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) {
|
|
2543
2517
|
continue;
|
|
2544
2518
|
}
|
|
2545
2519
|
|
|
@@ -2616,7 +2590,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
2616
2590
|
(typeof options === 'object') &&
|
|
2617
2591
|
('validateModifiedOnly' in options);
|
|
2618
2592
|
|
|
2619
|
-
const pathsToSkip =
|
|
2593
|
+
const pathsToSkip = (options && options.pathsToSkip) || null;
|
|
2620
2594
|
|
|
2621
2595
|
let shouldValidateModifiedOnly;
|
|
2622
2596
|
if (hasValidateModifiedOnlyOption) {
|
|
@@ -2877,19 +2851,21 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
2877
2851
|
}
|
|
2878
2852
|
const validating = {};
|
|
2879
2853
|
|
|
2880
|
-
paths.
|
|
2854
|
+
for (let i = 0, len = paths.length; i < len; ++i) {
|
|
2855
|
+
const path = paths[i];
|
|
2856
|
+
|
|
2881
2857
|
if (validating[path]) {
|
|
2882
|
-
|
|
2858
|
+
continue;
|
|
2883
2859
|
}
|
|
2884
2860
|
|
|
2885
2861
|
validating[path] = true;
|
|
2886
2862
|
|
|
2887
2863
|
const p = _this.$__schema.path(path);
|
|
2888
2864
|
if (!p) {
|
|
2889
|
-
|
|
2865
|
+
continue;
|
|
2890
2866
|
}
|
|
2891
2867
|
if (!_this.$isValid(path)) {
|
|
2892
|
-
|
|
2868
|
+
continue;
|
|
2893
2869
|
}
|
|
2894
2870
|
|
|
2895
2871
|
const val = _this.$__getValue(path);
|
|
@@ -2903,11 +2879,11 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
2903
2879
|
p.$isArraySubdocument ||
|
|
2904
2880
|
p.$isMongooseDocumentArray;
|
|
2905
2881
|
if (isSubdoc && err instanceof ValidationError) {
|
|
2906
|
-
|
|
2882
|
+
continue;
|
|
2907
2883
|
}
|
|
2908
2884
|
_this.invalidate(path, err, undefined, true);
|
|
2909
2885
|
}
|
|
2910
|
-
}
|
|
2886
|
+
}
|
|
2911
2887
|
|
|
2912
2888
|
const err = _this.$__.validationError;
|
|
2913
2889
|
_this.$__.validationError = undefined;
|
|
@@ -3066,7 +3042,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3066
3042
|
*
|
|
3067
3043
|
* @param {Object} [options] options optional options
|
|
3068
3044
|
* @param {Session} [options.session=null] the [session](https://docs.mongodb.com/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](api.html#document_Document-$session).
|
|
3069
|
-
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](
|
|
3045
|
+
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](https://mongoosejs.com//docs/guide.html#safe). Use the `w` option instead.
|
|
3070
3046
|
* @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
|
|
3071
3047
|
* @param {Boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
|
|
3072
3048
|
* @param {Number|String} [options.w] set the [write concern](https://docs.mongodb.com/manual/reference/write-concern/#w-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
|
|
@@ -3081,7 +3057,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3081
3057
|
* @throws {DocumentNotFoundError} if this [save updates an existing document](api.html#document_Document-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).
|
|
3082
3058
|
* @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
|
|
3083
3059
|
* @api public
|
|
3084
|
-
* @see middleware
|
|
3060
|
+
* @see middleware https://mongoosejs.com/docs/middleware.html
|
|
3085
3061
|
*/
|
|
3086
3062
|
|
|
3087
3063
|
/**
|
|
@@ -3131,7 +3107,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3131
3107
|
return _this.$__getValue(i);
|
|
3132
3108
|
})
|
|
3133
3109
|
.filter(function(val) {
|
|
3134
|
-
return val && val
|
|
3110
|
+
return val && Array.isArray(val) && utils.isMongooseDocumentArray(val) && val.length;
|
|
3135
3111
|
})
|
|
3136
3112
|
.forEach(function(array) {
|
|
3137
3113
|
let i = array.length;
|
|
@@ -3334,7 +3310,7 @@ Document.prototype.$__getArrayPathsToValidate = function() {
|
|
|
3334
3310
|
return this.$__getValue(i);
|
|
3335
3311
|
}.bind(this))
|
|
3336
3312
|
.filter(function(val) {
|
|
3337
|
-
return val && val
|
|
3313
|
+
return val && Array.isArray(val) && utils.isMongooseDocumentArray(val) && val.length;
|
|
3338
3314
|
}).reduce(function(seed, array) {
|
|
3339
3315
|
return seed.concat(array);
|
|
3340
3316
|
}, [])
|
|
@@ -3455,8 +3431,11 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3455
3431
|
};
|
|
3456
3432
|
|
|
3457
3433
|
const path = json ? 'toJSON' : 'toObject';
|
|
3458
|
-
const baseOptions =
|
|
3459
|
-
|
|
3434
|
+
const baseOptions = this.constructor &&
|
|
3435
|
+
this.constructor.base &&
|
|
3436
|
+
this.constructor.base.options &&
|
|
3437
|
+
get(this.constructor.base.options, path) || {};
|
|
3438
|
+
const schemaOptions = this.$__schema && this.$__schema.options || {};
|
|
3460
3439
|
// merge base default options with Schema's set default options if available.
|
|
3461
3440
|
// `clone` is necessary here because `utils.options` directly modifies the second input.
|
|
3462
3441
|
defaultOptions = utils.options(defaultOptions, clone(baseOptions));
|
|
@@ -3503,12 +3482,11 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3503
3482
|
}
|
|
3504
3483
|
|
|
3505
3484
|
const depopulate = options.depopulate ||
|
|
3506
|
-
|
|
3485
|
+
(options._parentOptions && options._parentOptions.depopulate || false);
|
|
3507
3486
|
// _isNested will only be true if this is not the top level document, we
|
|
3508
|
-
// should never depopulate
|
|
3487
|
+
// should never depopulate the top-level document
|
|
3509
3488
|
if (depopulate && options._isNested && this.$__.wasPopulated) {
|
|
3510
|
-
|
|
3511
|
-
return clone(this._id, cloneOptions);
|
|
3489
|
+
return clone(this.$__.wasPopulated.value || this._id, cloneOptions);
|
|
3512
3490
|
}
|
|
3513
3491
|
|
|
3514
3492
|
// merge default options with input options.
|
|
@@ -3583,7 +3561,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3583
3561
|
/**
|
|
3584
3562
|
* Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)).
|
|
3585
3563
|
*
|
|
3586
|
-
* Buffers are converted to instances of [mongodb.Binary](
|
|
3564
|
+
* Buffers are converted to instances of [mongodb.Binary](https://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html) for proper storage.
|
|
3587
3565
|
*
|
|
3588
3566
|
* ####Options:
|
|
3589
3567
|
*
|
|
@@ -3722,7 +3700,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3722
3700
|
* @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
|
|
3723
3701
|
* @param {Boolean} [options.useProjection=false] - If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
|
|
3724
3702
|
* @return {Object} js object
|
|
3725
|
-
* @see mongodb.Binary
|
|
3703
|
+
* @see mongodb.Binary https://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html
|
|
3726
3704
|
* @api public
|
|
3727
3705
|
* @memberOf Document
|
|
3728
3706
|
* @instance
|
|
@@ -3780,7 +3758,9 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
3780
3758
|
let assignPath;
|
|
3781
3759
|
let cur = self._doc;
|
|
3782
3760
|
let v;
|
|
3783
|
-
const aliases =
|
|
3761
|
+
const aliases = typeof (toObjectOptions && toObjectOptions.aliases) === 'boolean'
|
|
3762
|
+
? toObjectOptions.aliases
|
|
3763
|
+
: true;
|
|
3784
3764
|
|
|
3785
3765
|
let virtualsToApply = null;
|
|
3786
3766
|
if (Array.isArray(options.virtuals)) {
|
|
@@ -3974,15 +3954,20 @@ function omitDeselectedFields(self, json) {
|
|
|
3974
3954
|
}
|
|
3975
3955
|
|
|
3976
3956
|
/**
|
|
3977
|
-
* The return value of this method is used in calls to JSON.stringify(doc).
|
|
3957
|
+
* The return value of this method is used in calls to [`JSON.stringify(doc)`](https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript#the-tojson-function).
|
|
3978
3958
|
*
|
|
3979
3959
|
* This method accepts the same options as [Document#toObject](#document_Document-toObject). To apply the options to every document of your schema by default, set your [schemas](#schema_Schema) `toJSON` option to the same argument.
|
|
3980
3960
|
*
|
|
3981
|
-
* schema.set('toJSON', { virtuals: true })
|
|
3961
|
+
* schema.set('toJSON', { virtuals: true });
|
|
3962
|
+
*
|
|
3963
|
+
* There is one difference between `toJSON()` and `toObject()` options.
|
|
3964
|
+
* When you call `toJSON()`, the [`flattenMaps` option](./document.html#document_Document-toObject) defaults to `true`, because `JSON.stringify()` doesn't convert maps to objects by default.
|
|
3965
|
+
* When you call `toObject()`, the `flattenMaps` option is `false` by default.
|
|
3982
3966
|
*
|
|
3983
|
-
* See [schema options](/docs/guide.html#toJSON) for
|
|
3967
|
+
* See [schema options](/docs/guide.html#toJSON) for more information on setting `toJSON` option defaults.
|
|
3984
3968
|
*
|
|
3985
3969
|
* @param {Object} options
|
|
3970
|
+
* @param {Boolean} [options.flattenMaps=true] if true, convert Maps to [POJOs](https://masteringjs.io/tutorials/fundamentals/pojo). Useful if you want to `JSON.stringify()` the result.
|
|
3986
3971
|
* @return {Object}
|
|
3987
3972
|
* @see Document#toObject #document_Document-toObject
|
|
3988
3973
|
* @see JSON.stringify() in JavaScript https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html
|
|
@@ -4137,6 +4122,7 @@ Document.prototype.equals = function(doc) {
|
|
|
4137
4122
|
* @param {Object} [match] Conditions for the population query
|
|
4138
4123
|
* @param {Object} [options] Options for the population query (sort, etc)
|
|
4139
4124
|
* @param {String} [options.path=null] The path to populate.
|
|
4125
|
+
* @param {string|PopulateOptions} [options.populate=null] Recursively populate paths in the populated documents. See [deep populate docs](/docs/populate.html#deep-populate).
|
|
4140
4126
|
* @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.
|
|
4141
4127
|
* @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`](/docs/schematypes.html#schematype-options).
|
|
4142
4128
|
* @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.
|
|
@@ -4317,7 +4303,7 @@ Document.prototype.depopulate = function(path) {
|
|
|
4317
4303
|
|
|
4318
4304
|
let populatedIds;
|
|
4319
4305
|
const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
|
|
4320
|
-
const populated =
|
|
4306
|
+
const populated = this.$__ && this.$__.populated || {};
|
|
4321
4307
|
|
|
4322
4308
|
if (arguments.length === 0) {
|
|
4323
4309
|
// Depopulate all
|
|
@@ -8,7 +8,6 @@ const MongooseCollection = require('../../collection');
|
|
|
8
8
|
const MongooseError = require('../../error/mongooseError');
|
|
9
9
|
const Collection = require('mongodb').Collection;
|
|
10
10
|
const ObjectId = require('./objectid');
|
|
11
|
-
const get = require('../../helpers/get');
|
|
12
11
|
const getConstructorName = require('../../helpers/getConstructorName');
|
|
13
12
|
const stream = require('stream');
|
|
14
13
|
const util = require('util');
|
|
@@ -76,7 +75,11 @@ function iter(i) {
|
|
|
76
75
|
const collection = this.collection;
|
|
77
76
|
const args = Array.from(arguments);
|
|
78
77
|
const _this = this;
|
|
79
|
-
const debug =
|
|
78
|
+
const debug = _this &&
|
|
79
|
+
_this.conn &&
|
|
80
|
+
_this.conn.base &&
|
|
81
|
+
_this.conn.base.options &&
|
|
82
|
+
_this.conn.base.options.debug;
|
|
80
83
|
const lastArg = arguments[arguments.length - 1];
|
|
81
84
|
const opId = new ObjectId();
|
|
82
85
|
|
|
@@ -84,7 +87,7 @@ function iter(i) {
|
|
|
84
87
|
if (this.conn.$wasForceClosed) {
|
|
85
88
|
const error = new MongooseError('Connection was force closed');
|
|
86
89
|
if (args.length > 0 &&
|
|
87
|
-
|
|
90
|
+
typeof args[args.length - 1] === 'function') {
|
|
88
91
|
args[args.length - 1](error);
|
|
89
92
|
return;
|
|
90
93
|
} else {
|
|
@@ -368,7 +371,12 @@ function format(obj, sub, color, shell) {
|
|
|
368
371
|
formatDate(x, key, shell);
|
|
369
372
|
} else if (_constructorName === 'ClientSession') {
|
|
370
373
|
x[key] = inspectable('ClientSession("' +
|
|
371
|
-
|
|
374
|
+
(
|
|
375
|
+
x[key] &&
|
|
376
|
+
x[key].id &&
|
|
377
|
+
x[key].id.id &&
|
|
378
|
+
x[key].id.id.buffer || ''
|
|
379
|
+
).toString('hex') + '")');
|
|
372
380
|
} else if (Array.isArray(x[key])) {
|
|
373
381
|
x[key] = x[key].map(map);
|
|
374
382
|
} else if (error != null) {
|
|
@@ -137,6 +137,17 @@ NativeConnection.prototype.doClose = function(force, fn) {
|
|
|
137
137
|
return this;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
let skipCloseClient = false;
|
|
141
|
+
if (force != null && typeof force === 'object') {
|
|
142
|
+
skipCloseClient = force.skipCloseClient;
|
|
143
|
+
force = force.force;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (skipCloseClient) {
|
|
147
|
+
immediate(() => fn());
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
|
|
140
151
|
this.client.close(force, (err, res) => {
|
|
141
152
|
// Defer because the driver will wait at least 1ms before finishing closing
|
|
142
153
|
// the pool, see https://github.com/mongodb-js/mongodb-core/blob/a8f8e4ce41936babc3b9112bf42d609779f03b39/lib/connection/pool.js#L1026-L1030.
|
package/lib/error/cast.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const MongooseError = require('./mongooseError');
|
|
8
|
-
const get = require('../helpers/get');
|
|
9
8
|
const util = require('util');
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -111,7 +110,9 @@ function getValueType(value) {
|
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
function getMessageFormat(schemaType) {
|
|
114
|
-
const messageFormat =
|
|
113
|
+
const messageFormat = schemaType &&
|
|
114
|
+
schemaType.options &&
|
|
115
|
+
schemaType.options.cast || null;
|
|
115
116
|
if (typeof messageFormat === 'string') {
|
|
116
117
|
return messageFormat;
|
|
117
118
|
}
|
package/lib/helpers/clone.js
CHANGED
|
@@ -41,15 +41,24 @@ function clone(obj, options, isArrayChild) {
|
|
|
41
41
|
if (options && options._skipSingleNestedGetters && obj.$isSingleNested) {
|
|
42
42
|
options = Object.assign({}, options, { getters: false });
|
|
43
43
|
}
|
|
44
|
+
const isSingleNested = obj.$isSingleNested;
|
|
44
45
|
|
|
45
46
|
if (utils.isPOJO(obj) && obj.$__ != null && obj._doc != null) {
|
|
46
47
|
return obj._doc;
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
let ret;
|
|
49
51
|
if (options && options.json && typeof obj.toJSON === 'function') {
|
|
50
|
-
|
|
52
|
+
ret = obj.toJSON(options);
|
|
53
|
+
} else {
|
|
54
|
+
ret = obj.toObject(options);
|
|
51
55
|
}
|
|
52
|
-
|
|
56
|
+
|
|
57
|
+
if (options && options.minimize && isSingleNested && Object.keys(ret).length === 0) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return ret;
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
const objConstructor = obj.constructor;
|
|
@@ -27,16 +27,15 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
27
27
|
const enqueue = asyncQueue();
|
|
28
28
|
|
|
29
29
|
return promiseOrCallback(callback, cb => {
|
|
30
|
+
|
|
30
31
|
if (batchSize != null) {
|
|
31
32
|
if (typeof batchSize !== 'number') {
|
|
32
33
|
throw new TypeError('batchSize must be a number');
|
|
33
|
-
}
|
|
34
|
-
|
|
34
|
+
} else if (!Number.isInteger(batchSize)) {
|
|
35
|
+
throw new TypeError('batchSize must be an integer');
|
|
36
|
+
} else if (batchSize < 1) {
|
|
35
37
|
throw new TypeError('batchSize must be at least 1');
|
|
36
38
|
}
|
|
37
|
-
if (batchSize !== Math.floor(batchSize)) {
|
|
38
|
-
throw new TypeError('batchSize must be a positive integer');
|
|
39
|
-
}
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
iterate(cb);
|
|
@@ -71,7 +70,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
71
70
|
drained = true;
|
|
72
71
|
if (handleResultsInProgress <= 0) {
|
|
73
72
|
finalCallback(null);
|
|
74
|
-
} else if (batchSize
|
|
73
|
+
} else if (batchSize && documentsBatch.length) {
|
|
75
74
|
handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
|
|
76
75
|
}
|
|
77
76
|
return done();
|
|
@@ -83,20 +82,20 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
83
82
|
// make sure we know that we still have a result to handle re: #8422
|
|
84
83
|
immediate(() => done());
|
|
85
84
|
|
|
86
|
-
if (batchSize
|
|
85
|
+
if (batchSize) {
|
|
87
86
|
documentsBatch.push(doc);
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
// If the current documents size is less than the provided patch size don't process the documents yet
|
|
91
|
-
if (batchSize
|
|
92
|
-
|
|
90
|
+
if (batchSize && documentsBatch.length !== batchSize) {
|
|
91
|
+
immediate(() => enqueue(fetch));
|
|
93
92
|
return;
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
const docsToProcess = batchSize
|
|
95
|
+
const docsToProcess = batchSize ? documentsBatch : doc;
|
|
97
96
|
|
|
98
97
|
function handleNextResultCallBack(err) {
|
|
99
|
-
if (batchSize
|
|
98
|
+
if (batchSize) {
|
|
100
99
|
handleResultsInProgress -= documentsBatch.length;
|
|
101
100
|
documentsBatch = [];
|
|
102
101
|
} else {
|
|
@@ -110,7 +109,7 @@ module.exports = function eachAsync(next, fn, options, callback) {
|
|
|
110
109
|
return finalCallback(null);
|
|
111
110
|
}
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
immediate(() => enqueue(fetch));
|
|
114
113
|
}
|
|
115
114
|
|
|
116
115
|
handleNextResult(docsToProcess, currentDocumentIndex++, handleNextResultCallBack);
|
|
@@ -139,7 +138,10 @@ function asyncQueue() {
|
|
|
139
138
|
let id = 0;
|
|
140
139
|
|
|
141
140
|
return function enqueue(fn) {
|
|
142
|
-
if (
|
|
141
|
+
if (
|
|
142
|
+
inProgress === null &&
|
|
143
|
+
_queue.length === 0
|
|
144
|
+
) {
|
|
143
145
|
inProgress = id++;
|
|
144
146
|
return fn(_step);
|
|
145
147
|
}
|
|
@@ -147,11 +149,12 @@ function asyncQueue() {
|
|
|
147
149
|
};
|
|
148
150
|
|
|
149
151
|
function _step() {
|
|
150
|
-
|
|
151
|
-
if (_queue.length > 0) {
|
|
152
|
+
if (_queue.length !== 0) {
|
|
152
153
|
inProgress = id++;
|
|
153
154
|
const fn = _queue.shift();
|
|
154
155
|
fn(_step);
|
|
156
|
+
} else {
|
|
157
|
+
inProgress = null;
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
160
|
}
|
|
@@ -12,6 +12,7 @@ module.exports = function cleanModifiedSubpaths(doc, path, options) {
|
|
|
12
12
|
if (!doc) {
|
|
13
13
|
return deleted;
|
|
14
14
|
}
|
|
15
|
+
|
|
15
16
|
for (const modifiedPath of Object.keys(doc.$__.activePaths.states.modify)) {
|
|
16
17
|
if (skipDocArrays) {
|
|
17
18
|
const schemaType = doc.$__schema.path(modifiedPath);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const documentSchemaSymbol = require('../../helpers/symbols').documentSchemaSymbol;
|
|
4
|
-
const get = require('../../helpers/get');
|
|
5
4
|
const internalToObjectOptions = require('../../options').internalToObjectOptions;
|
|
6
5
|
const utils = require('../../utils');
|
|
7
6
|
|
|
@@ -93,7 +92,11 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
|
|
|
93
92
|
writable: false,
|
|
94
93
|
value: function() {
|
|
95
94
|
return utils.clone(_this.get(path, null, {
|
|
96
|
-
virtuals:
|
|
95
|
+
virtuals: this &&
|
|
96
|
+
this.schema &&
|
|
97
|
+
this.schema.options &&
|
|
98
|
+
this.schema.options.toObject &&
|
|
99
|
+
this.schema.options.toObject.virtuals || null
|
|
97
100
|
}));
|
|
98
101
|
}
|
|
99
102
|
});
|
|
@@ -104,7 +107,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
|
|
|
104
107
|
writable: false,
|
|
105
108
|
value: function() {
|
|
106
109
|
return _this.get(path, null, {
|
|
107
|
-
virtuals:
|
|
110
|
+
virtuals: this && this.schema && this.schema.options && this.schema.options.toObject && this.schema.options.toObject.virtuals || null
|
|
108
111
|
});
|
|
109
112
|
}
|
|
110
113
|
});
|
|
@@ -115,7 +118,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
|
|
|
115
118
|
writable: false,
|
|
116
119
|
value: function() {
|
|
117
120
|
return _this.get(path, null, {
|
|
118
|
-
virtuals:
|
|
121
|
+
virtuals: this && this.schema && this.schema.options && this.schema.options.toJSON && this.schema.options.toJSON.virtuals || null
|
|
119
122
|
});
|
|
120
123
|
}
|
|
121
124
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = function decorateDiscriminatorIndexOptions(schema, indexOptions) {
|
|
4
|
+
// If the model is a discriminator and has an index, add a
|
|
5
|
+
// partialFilterExpression by default so the index will only apply
|
|
6
|
+
// to that discriminator.
|
|
7
|
+
const discriminatorName = schema.discriminatorMapping && schema.discriminatorMapping.value;
|
|
8
|
+
if (discriminatorName && !('sparse' in indexOptions)) {
|
|
9
|
+
const discriminatorKey = schema.options.discriminatorKey;
|
|
10
|
+
indexOptions.partialFilterExpression = indexOptions.partialFilterExpression || {};
|
|
11
|
+
indexOptions.partialFilterExpression[discriminatorKey] = discriminatorName;
|
|
12
|
+
}
|
|
13
|
+
return indexOptions;
|
|
14
|
+
};
|