mongoose 6.1.10 → 6.2.3
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 +154 -0
- package/CHANGELOG.md +73 -0
- package/dist/browser.umd.js +233 -222
- package/index.js +5 -1
- package/lib/aggregate.js +23 -28
- package/lib/browserDocument.js +1 -1
- package/lib/cast/number.js +2 -3
- package/lib/cast.js +9 -7
- package/lib/connection.js +76 -24
- package/lib/cursor/AggregationCursor.js +12 -7
- package/lib/cursor/QueryCursor.js +11 -6
- package/lib/document.js +131 -122
- 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/error/index.js +11 -0
- package/lib/error/syncIndexes.js +30 -0
- package/lib/helpers/clone.js +51 -29
- package/lib/helpers/common.js +2 -2
- package/lib/helpers/cursor/eachAsync.js +18 -15
- package/lib/helpers/document/compile.js +7 -4
- package/lib/helpers/getFunctionName.js +6 -4
- package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
- package/lib/helpers/indexes/getRelatedIndexes.js +59 -0
- package/lib/helpers/isMongooseObject.js +9 -8
- package/lib/helpers/isObject.js +4 -4
- package/lib/helpers/model/discriminator.js +2 -1
- package/lib/helpers/path/parentPaths.js +10 -5
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
- package/lib/helpers/populate/assignVals.js +12 -4
- package/lib/helpers/populate/getModelsMapForPopulate.js +4 -4
- package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
- package/lib/helpers/populate/modelNamesFromRefPath.js +4 -3
- 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 +279 -0
- package/lib/helpers/query/castUpdate.js +6 -2
- package/lib/helpers/query/hasDollarKeys.js +7 -3
- package/lib/helpers/query/isOperator.js +5 -2
- package/lib/helpers/schema/applyPlugins.js +11 -0
- package/lib/helpers/schema/getIndexes.js +6 -2
- package/lib/helpers/schema/getPath.js +4 -2
- package/lib/helpers/timestamps/setupTimestamps.js +3 -8
- package/lib/index.js +26 -19
- package/lib/internal.js +10 -2
- package/lib/model.js +196 -171
- package/lib/options/SchemaTypeOptions.js +1 -1
- package/lib/plugins/trackTransaction.js +5 -4
- package/lib/query.js +159 -146
- package/lib/queryhelpers.js +10 -10
- package/lib/schema/SubdocumentPath.js +4 -3
- package/lib/schema/array.js +30 -21
- 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 -11
- package/lib/schema/number.js +1 -1
- package/lib/schema/objectid.js +2 -2
- package/lib/schema/string.js +4 -4
- package/lib/schema.js +13 -8
- package/lib/schematype.js +86 -40
- package/lib/types/ArraySubdocument.js +2 -1
- package/lib/types/DocumentArray/index.js +10 -27
- package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
- package/lib/types/DocumentArray/methods/index.js +15 -3
- package/lib/types/array/index.js +22 -21
- package/lib/types/array/isMongooseArray.js +5 -0
- package/lib/types/array/methods/index.js +22 -23
- package/lib/types/buffer.js +3 -3
- package/lib/types/map.js +3 -4
- package/lib/utils.js +19 -10
- package/package.json +34 -168
- package/tools/repl.js +1 -1
- package/tsconfig.json +8 -0
- package/types/Error.d.ts +129 -0
- package/types/PipelineStage.d.ts +272 -0
- package/{index.d.ts → types/index.d.ts} +169 -481
- 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
|
|
@@ -90,7 +91,7 @@ function Document(obj, fields, skipId, options) {
|
|
|
90
91
|
options = arguments[4] || {};
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
this.$__ = new InternalCache;
|
|
94
|
+
this.$__ = new InternalCache();
|
|
94
95
|
this.$isNew = 'isNew' in options ? options.isNew : true;
|
|
95
96
|
|
|
96
97
|
if ('priorDoc' in options) {
|
|
@@ -417,33 +418,6 @@ Object.defineProperty(Document.prototype, '$op', {
|
|
|
417
418
|
}
|
|
418
419
|
});
|
|
419
420
|
|
|
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
421
|
/*!
|
|
448
422
|
* ignore
|
|
449
423
|
*/
|
|
@@ -479,7 +453,8 @@ function $__applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSet
|
|
|
479
453
|
break;
|
|
480
454
|
}
|
|
481
455
|
} else if (exclude === false && fields && !included) {
|
|
482
|
-
|
|
456
|
+
const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray;
|
|
457
|
+
if (curPath in fields || (hasSubpaths && hasIncludedChildren[curPath])) {
|
|
483
458
|
included = true;
|
|
484
459
|
} else if (!hasIncludedChildren[curPath]) {
|
|
485
460
|
break;
|
|
@@ -795,11 +770,12 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
795
770
|
|
|
796
771
|
const keys = Object.keys(obj);
|
|
797
772
|
const len = keys.length;
|
|
798
|
-
let
|
|
773
|
+
let schemaType;
|
|
799
774
|
let path;
|
|
800
775
|
let i;
|
|
801
776
|
let index = 0;
|
|
802
777
|
const strict = self.$__.strictMode;
|
|
778
|
+
const docSchema = self.$__schema;
|
|
803
779
|
|
|
804
780
|
while (index < len) {
|
|
805
781
|
_init(index++);
|
|
@@ -808,25 +784,27 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
808
784
|
function _init(index) {
|
|
809
785
|
i = keys[index];
|
|
810
786
|
path = prefix + i;
|
|
811
|
-
|
|
787
|
+
schemaType = docSchema.path(path);
|
|
812
788
|
|
|
813
789
|
// Should still work if not a model-level discriminator, but should not be
|
|
814
790
|
// necessary. This is *only* to catch the case where we queried using the
|
|
815
791
|
// base model and the discriminated model has a projection
|
|
816
|
-
if (
|
|
792
|
+
if (docSchema.$isRootDiscriminator && !self.$__isSelected(path)) {
|
|
817
793
|
return;
|
|
818
794
|
}
|
|
819
795
|
|
|
820
|
-
if (!
|
|
796
|
+
if (!schemaType && utils.isPOJO(obj[i])) {
|
|
821
797
|
// assume nested object
|
|
822
798
|
if (!doc[i]) {
|
|
823
799
|
doc[i] = {};
|
|
800
|
+
if (!strict && !(i in docSchema.tree) && !(i in docSchema.methods) && !(i in docSchema.virtuals)) {
|
|
801
|
+
self[i] = doc[i];
|
|
802
|
+
}
|
|
824
803
|
}
|
|
825
804
|
init(self, obj[i], doc[i], opts, path + '.');
|
|
826
|
-
} else if (!
|
|
805
|
+
} else if (!schemaType) {
|
|
827
806
|
doc[i] = obj[i];
|
|
828
|
-
if (!strict
|
|
829
|
-
// Set top-level properties that aren't in the schema if strict is false
|
|
807
|
+
if (!strict) {
|
|
830
808
|
self[i] = obj[i];
|
|
831
809
|
}
|
|
832
810
|
} else {
|
|
@@ -835,13 +813,13 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
835
813
|
delete doc[i];
|
|
836
814
|
}
|
|
837
815
|
if (obj[i] === null) {
|
|
838
|
-
doc[i] =
|
|
816
|
+
doc[i] = schemaType._castNullish(null);
|
|
839
817
|
} else if (obj[i] !== undefined) {
|
|
840
818
|
const wasPopulated = obj[i].$__ == null ? null : obj[i].$__.wasPopulated;
|
|
841
819
|
|
|
842
|
-
if (
|
|
820
|
+
if (schemaType && !wasPopulated) {
|
|
843
821
|
try {
|
|
844
|
-
doc[i] =
|
|
822
|
+
doc[i] = schemaType.cast(obj[i], self, true);
|
|
845
823
|
} catch (e) {
|
|
846
824
|
self.invalidate(e.path, new ValidatorError({
|
|
847
825
|
path: e.path,
|
|
@@ -911,9 +889,9 @@ Document.prototype.update = function update() {
|
|
|
911
889
|
*
|
|
912
890
|
* @see Model.updateOne #model_Model.updateOne
|
|
913
891
|
* @param {Object} doc
|
|
914
|
-
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](
|
|
892
|
+
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api.html#query_Query-setOptions)
|
|
915
893
|
* @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).
|
|
916
|
-
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](
|
|
894
|
+
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
917
895
|
* @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.
|
|
918
896
|
* @param {Function} callback
|
|
919
897
|
* @return {Query}
|
|
@@ -1116,7 +1094,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1116
1094
|
|
|
1117
1095
|
// `_skipMinimizeTopLevel` is because we may have deleted the top-level
|
|
1118
1096
|
// nested key to ensure key order.
|
|
1119
|
-
const _skipMinimizeTopLevel =
|
|
1097
|
+
const _skipMinimizeTopLevel = options._skipMinimizeTopLevel || false;
|
|
1120
1098
|
if (len === 0 && _skipMinimizeTopLevel) {
|
|
1121
1099
|
delete options._skipMinimizeTopLevel;
|
|
1122
1100
|
if (val) {
|
|
@@ -1135,7 +1113,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1135
1113
|
// them to ensure we keep the user's key order.
|
|
1136
1114
|
if (type === true &&
|
|
1137
1115
|
!prefix &&
|
|
1138
|
-
|
|
1116
|
+
valForKey != null &&
|
|
1139
1117
|
pathtype === 'nested' &&
|
|
1140
1118
|
this._doc[key] != null) {
|
|
1141
1119
|
delete this._doc[key];
|
|
@@ -1260,7 +1238,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1260
1238
|
const parts = path.indexOf('.') === -1 ? [path] : path.split('.');
|
|
1261
1239
|
|
|
1262
1240
|
// Might need to change path for top-level alias
|
|
1263
|
-
if (typeof this.$__schema.aliases[parts[0]]
|
|
1241
|
+
if (typeof this.$__schema.aliases[parts[0]] === 'string') {
|
|
1264
1242
|
parts[0] = this.$__schema.aliases[parts[0]];
|
|
1265
1243
|
}
|
|
1266
1244
|
|
|
@@ -1313,7 +1291,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1313
1291
|
let curPath = '';
|
|
1314
1292
|
for (i = 0; i < parts.length - 1; ++i) {
|
|
1315
1293
|
cur = cur[parts[i]];
|
|
1316
|
-
curPath += (curPath.length
|
|
1294
|
+
curPath += (curPath.length !== 0 ? '.' : '') + parts[i];
|
|
1317
1295
|
if (!cur) {
|
|
1318
1296
|
this.$set(curPath, {});
|
|
1319
1297
|
// Hack re: gh-5800. If nested field is not selected, it probably exists
|
|
@@ -1336,7 +1314,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1336
1314
|
if (parts.length <= 1) {
|
|
1337
1315
|
pathToMark = path;
|
|
1338
1316
|
} else {
|
|
1339
|
-
|
|
1317
|
+
const len = parts.length;
|
|
1318
|
+
for (i = 0; i < len; ++i) {
|
|
1340
1319
|
const subpath = parts.slice(0, i + 1).join('.');
|
|
1341
1320
|
if (this.$get(subpath, null, { getters: false }) === null) {
|
|
1342
1321
|
pathToMark = subpath;
|
|
@@ -1361,7 +1340,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1361
1340
|
_markValidSubpaths(this, path);
|
|
1362
1341
|
}
|
|
1363
1342
|
|
|
1364
|
-
if (
|
|
1343
|
+
if (val != null && merge && schema.$isSingleNested) {
|
|
1365
1344
|
if (val instanceof Document) {
|
|
1366
1345
|
val = val.toObject({ virtuals: false, transform: false });
|
|
1367
1346
|
}
|
|
@@ -1403,8 +1382,9 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1403
1382
|
|
|
1404
1383
|
let didPopulate = false;
|
|
1405
1384
|
if (refMatches && val instanceof Document) {
|
|
1406
|
-
|
|
1407
|
-
val
|
|
1385
|
+
const unpopulatedValue = (schema && schema.$isSingleNested) ? schema.cast(val, this) : val._id;
|
|
1386
|
+
this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
|
|
1387
|
+
val.$__.wasPopulated = { value: unpopulatedValue };
|
|
1408
1388
|
didPopulate = true;
|
|
1409
1389
|
}
|
|
1410
1390
|
|
|
@@ -1418,7 +1398,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1418
1398
|
this.$populated(path, val.map(function(v) { return v._id; }), popOpts);
|
|
1419
1399
|
|
|
1420
1400
|
for (const doc of val) {
|
|
1421
|
-
doc.$__.wasPopulated =
|
|
1401
|
+
doc.$__.wasPopulated = { value: doc._id };
|
|
1422
1402
|
}
|
|
1423
1403
|
didPopulate = true;
|
|
1424
1404
|
}
|
|
@@ -1431,9 +1411,10 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1431
1411
|
val = schema.applySetters(val, this, false, priorVal);
|
|
1432
1412
|
}
|
|
1433
1413
|
|
|
1434
|
-
if (
|
|
1435
|
-
Array.isArray(
|
|
1436
|
-
|
|
1414
|
+
if (Array.isArray(val) &&
|
|
1415
|
+
!Array.isArray(schema) &&
|
|
1416
|
+
schema.$isMongooseDocumentArray &&
|
|
1417
|
+
val.length !== 0 &&
|
|
1437
1418
|
val[0] != null &&
|
|
1438
1419
|
val[0].$__ != null &&
|
|
1439
1420
|
val[0].$__.populated != null) {
|
|
@@ -1459,7 +1440,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1459
1440
|
delete this.$__.populated[path];
|
|
1460
1441
|
}
|
|
1461
1442
|
|
|
1462
|
-
if (
|
|
1443
|
+
if (val != null && schema.$isSingleNested) {
|
|
1463
1444
|
_checkImmutableSubpaths(val, schema, priorVal);
|
|
1464
1445
|
}
|
|
1465
1446
|
|
|
@@ -1652,11 +1633,11 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1652
1633
|
|
|
1653
1634
|
// handle directly setting arrays (gh-1126)
|
|
1654
1635
|
MongooseArray || (MongooseArray = require('./types/array'));
|
|
1655
|
-
if (val &&
|
|
1636
|
+
if (val && utils.isMongooseArray(val)) {
|
|
1656
1637
|
val._registerAtomic('$set', val);
|
|
1657
1638
|
|
|
1658
1639
|
// Update embedded document parent references (gh-5189)
|
|
1659
|
-
if (
|
|
1640
|
+
if (utils.isMongooseDocumentArray(val)) {
|
|
1660
1641
|
val.forEach(function(item) {
|
|
1661
1642
|
item && item.__parentArray && (item.__parentArray = val);
|
|
1662
1643
|
});
|
|
@@ -1670,10 +1651,10 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1670
1651
|
}
|
|
1671
1652
|
});
|
|
1672
1653
|
}
|
|
1673
|
-
} else if (Array.isArray(val) &&
|
|
1654
|
+
} else if (Array.isArray(val) && Array.isArray(priorVal) && utils.isMongooseArray(val) && utils.isMongooseArray(priorVal)) {
|
|
1674
1655
|
val[arrayAtomicsSymbol] = priorVal[arrayAtomicsSymbol];
|
|
1675
1656
|
val[arrayAtomicsBackupSymbol] = priorVal[arrayAtomicsBackupSymbol];
|
|
1676
|
-
if (
|
|
1657
|
+
if (utils.isMongooseDocumentArray(val)) {
|
|
1677
1658
|
val.forEach(doc => { doc.isNew = false; });
|
|
1678
1659
|
}
|
|
1679
1660
|
}
|
|
@@ -1702,7 +1683,7 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1702
1683
|
obj = obj[parts[i]];
|
|
1703
1684
|
} else if (obj[parts[i]] && obj[parts[i]] instanceof Embedded) {
|
|
1704
1685
|
obj = obj[parts[i]];
|
|
1705
|
-
} else if (obj[parts[i]] && obj[parts[i]].$isSingleNested) {
|
|
1686
|
+
} else if (obj[parts[i]] && !Array.isArray(obj[parts[i]]) && obj[parts[i]].$isSingleNested) {
|
|
1706
1687
|
obj = obj[parts[i]];
|
|
1707
1688
|
} else if (obj[parts[i]] && Array.isArray(obj[parts[i]])) {
|
|
1708
1689
|
obj = obj[parts[i]];
|
|
@@ -1782,7 +1763,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1782
1763
|
}
|
|
1783
1764
|
|
|
1784
1765
|
// Might need to change path for top-level alias
|
|
1785
|
-
if (typeof this.$__schema.aliases[pieces[0]]
|
|
1766
|
+
if (typeof this.$__schema.aliases[pieces[0]] === 'string') {
|
|
1786
1767
|
pieces[0] = this.$__schema.aliases[pieces[0]];
|
|
1787
1768
|
}
|
|
1788
1769
|
|
|
@@ -1963,7 +1944,7 @@ Document.prototype.$isEmpty = function(path) {
|
|
|
1963
1944
|
transform: false
|
|
1964
1945
|
};
|
|
1965
1946
|
|
|
1966
|
-
if (arguments.length
|
|
1947
|
+
if (arguments.length !== 0) {
|
|
1967
1948
|
const v = this.$get(path);
|
|
1968
1949
|
if (v == null) {
|
|
1969
1950
|
return true;
|
|
@@ -2006,51 +1987,60 @@ function _isEmpty(v) {
|
|
|
2006
1987
|
|
|
2007
1988
|
Document.prototype.modifiedPaths = function(options) {
|
|
2008
1989
|
options = options || {};
|
|
1990
|
+
|
|
2009
1991
|
const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
|
|
2010
|
-
const
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
1992
|
+
const result = new Set();
|
|
1993
|
+
|
|
1994
|
+
let i = 0;
|
|
1995
|
+
let j = 0;
|
|
1996
|
+
const len = directModifiedPaths.length;
|
|
1997
|
+
|
|
1998
|
+
for (i = 0; i < len; ++i) {
|
|
1999
|
+
const path = directModifiedPaths[i];
|
|
2000
|
+
const parts = parentPaths(path);
|
|
2001
|
+
const pLen = parts.length;
|
|
2002
|
+
|
|
2003
|
+
for (j = 0; j < pLen; ++j) {
|
|
2004
|
+
result.add(parts[j]);
|
|
2005
|
+
}
|
|
2018
2006
|
|
|
2019
2007
|
if (!options.includeChildren) {
|
|
2020
|
-
|
|
2008
|
+
continue;
|
|
2021
2009
|
}
|
|
2022
2010
|
|
|
2023
|
-
let
|
|
2024
|
-
|
|
2011
|
+
let ii = 0;
|
|
2012
|
+
let cur = this.$get(path);
|
|
2013
|
+
if (typeof cur === 'object' && cur !== null) {
|
|
2025
2014
|
if (cur._doc) {
|
|
2026
2015
|
cur = cur._doc;
|
|
2027
2016
|
}
|
|
2017
|
+
const len = cur.length;
|
|
2028
2018
|
if (Array.isArray(cur)) {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
if (
|
|
2032
|
-
|
|
2033
|
-
if (cur[
|
|
2034
|
-
const modified = cur[
|
|
2035
|
-
|
|
2036
|
-
|
|
2019
|
+
for (ii = 0; ii < len; ++ii) {
|
|
2020
|
+
const subPath = path + '.' + ii;
|
|
2021
|
+
if (!result.has(subPath)) {
|
|
2022
|
+
result.add(subPath);
|
|
2023
|
+
if (cur[ii] != null && cur[ii].$__) {
|
|
2024
|
+
const modified = cur[ii].modifiedPaths();
|
|
2025
|
+
let iii = 0;
|
|
2026
|
+
const iiiLen = modified.length;
|
|
2027
|
+
for (iii = 0; iii < iiiLen; ++iii) {
|
|
2028
|
+
result.add(subPath + '.' + modified[iii]);
|
|
2037
2029
|
}
|
|
2038
2030
|
}
|
|
2039
2031
|
}
|
|
2040
2032
|
}
|
|
2041
2033
|
} else {
|
|
2042
|
-
Object.keys(cur)
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
});
|
|
2034
|
+
const keys = Object.keys(cur);
|
|
2035
|
+
let ii = 0;
|
|
2036
|
+
const len = keys.length;
|
|
2037
|
+
for (ii = 0; ii < len; ++ii) {
|
|
2038
|
+
result.add(path + '.' + keys[ii]);
|
|
2039
|
+
}
|
|
2049
2040
|
}
|
|
2050
2041
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
}, []);
|
|
2042
|
+
}
|
|
2043
|
+
return Array.from(result);
|
|
2054
2044
|
};
|
|
2055
2045
|
|
|
2056
2046
|
Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
|
|
@@ -2448,7 +2438,12 @@ Document.prototype.$validate = Document.prototype.validate;
|
|
|
2448
2438
|
*/
|
|
2449
2439
|
|
|
2450
2440
|
function _evaluateRequiredFunctions(doc) {
|
|
2451
|
-
Object.keys(doc.$__.activePaths.states.require)
|
|
2441
|
+
const requiredFields = Object.keys(doc.$__.activePaths.states.require);
|
|
2442
|
+
let i = 0;
|
|
2443
|
+
const len = requiredFields.length;
|
|
2444
|
+
for (i = 0; i < len; ++i) {
|
|
2445
|
+
const path = requiredFields[i];
|
|
2446
|
+
|
|
2452
2447
|
const p = doc.$__schema.path(path);
|
|
2453
2448
|
|
|
2454
2449
|
if (p != null && typeof p.originalRequiredValue === 'function') {
|
|
@@ -2459,7 +2454,7 @@ function _evaluateRequiredFunctions(doc) {
|
|
|
2459
2454
|
doc.invalidate(path, err);
|
|
2460
2455
|
}
|
|
2461
2456
|
}
|
|
2462
|
-
}
|
|
2457
|
+
}
|
|
2463
2458
|
}
|
|
2464
2459
|
|
|
2465
2460
|
/*!
|
|
@@ -2520,7 +2515,9 @@ function _getPathsToValidate(doc) {
|
|
|
2520
2515
|
// To avoid potential performance issues, skip doc arrays whose children
|
|
2521
2516
|
// are not required. `getPositionalPathType()` may be slow, so avoid
|
|
2522
2517
|
// it unless we have a case of #6364
|
|
2523
|
-
(
|
|
2518
|
+
(!Array.isArray(_pathType) &&
|
|
2519
|
+
_pathType.$isMongooseDocumentArray &&
|
|
2520
|
+
!(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) {
|
|
2524
2521
|
continue;
|
|
2525
2522
|
}
|
|
2526
2523
|
|
|
@@ -2597,7 +2594,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
2597
2594
|
(typeof options === 'object') &&
|
|
2598
2595
|
('validateModifiedOnly' in options);
|
|
2599
2596
|
|
|
2600
|
-
const pathsToSkip =
|
|
2597
|
+
const pathsToSkip = (options && options.pathsToSkip) || null;
|
|
2601
2598
|
|
|
2602
2599
|
let shouldValidateModifiedOnly;
|
|
2603
2600
|
if (hasValidateModifiedOnlyOption) {
|
|
@@ -2858,19 +2855,21 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
2858
2855
|
}
|
|
2859
2856
|
const validating = {};
|
|
2860
2857
|
|
|
2861
|
-
paths.
|
|
2858
|
+
for (let i = 0, len = paths.length; i < len; ++i) {
|
|
2859
|
+
const path = paths[i];
|
|
2860
|
+
|
|
2862
2861
|
if (validating[path]) {
|
|
2863
|
-
|
|
2862
|
+
continue;
|
|
2864
2863
|
}
|
|
2865
2864
|
|
|
2866
2865
|
validating[path] = true;
|
|
2867
2866
|
|
|
2868
2867
|
const p = _this.$__schema.path(path);
|
|
2869
2868
|
if (!p) {
|
|
2870
|
-
|
|
2869
|
+
continue;
|
|
2871
2870
|
}
|
|
2872
2871
|
if (!_this.$isValid(path)) {
|
|
2873
|
-
|
|
2872
|
+
continue;
|
|
2874
2873
|
}
|
|
2875
2874
|
|
|
2876
2875
|
const val = _this.$__getValue(path);
|
|
@@ -2884,11 +2883,11 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
2884
2883
|
p.$isArraySubdocument ||
|
|
2885
2884
|
p.$isMongooseDocumentArray;
|
|
2886
2885
|
if (isSubdoc && err instanceof ValidationError) {
|
|
2887
|
-
|
|
2886
|
+
continue;
|
|
2888
2887
|
}
|
|
2889
2888
|
_this.invalidate(path, err, undefined, true);
|
|
2890
2889
|
}
|
|
2891
|
-
}
|
|
2890
|
+
}
|
|
2892
2891
|
|
|
2893
2892
|
const err = _this.$__.validationError;
|
|
2894
2893
|
_this.$__.validationError = undefined;
|
|
@@ -3047,7 +3046,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3047
3046
|
*
|
|
3048
3047
|
* @param {Object} [options] options optional options
|
|
3049
3048
|
* @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).
|
|
3050
|
-
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](
|
|
3049
|
+
* @param {Object} [options.safe] (DEPRECATED) overrides [schema's safe option](https://mongoosejs.com//docs/guide.html#safe). Use the `w` option instead.
|
|
3051
3050
|
* @param {Boolean} [options.validateBeforeSave] set to false to save without validating.
|
|
3052
3051
|
* @param {Boolean} [options.validateModifiedOnly=false] If `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
|
|
3053
3052
|
* @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)
|
|
@@ -3062,7 +3061,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3062
3061
|
* @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).
|
|
3063
3062
|
* @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
|
|
3064
3063
|
* @api public
|
|
3065
|
-
* @see middleware
|
|
3064
|
+
* @see middleware https://mongoosejs.com/docs/middleware.html
|
|
3066
3065
|
*/
|
|
3067
3066
|
|
|
3068
3067
|
/**
|
|
@@ -3112,7 +3111,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3112
3111
|
return _this.$__getValue(i);
|
|
3113
3112
|
})
|
|
3114
3113
|
.filter(function(val) {
|
|
3115
|
-
return val && val
|
|
3114
|
+
return val && Array.isArray(val) && utils.isMongooseDocumentArray(val) && val.length;
|
|
3116
3115
|
})
|
|
3117
3116
|
.forEach(function(array) {
|
|
3118
3117
|
let i = array.length;
|
|
@@ -3135,7 +3134,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3135
3134
|
return _this.$__getValue(i);
|
|
3136
3135
|
}).
|
|
3137
3136
|
filter(function(val) {
|
|
3138
|
-
return val && val.$isSingleNested;
|
|
3137
|
+
return val && !Array.isArray(val) && val.$isSingleNested;
|
|
3139
3138
|
}).
|
|
3140
3139
|
forEach(function(doc) {
|
|
3141
3140
|
doc.$__reset();
|
|
@@ -3315,7 +3314,7 @@ Document.prototype.$__getArrayPathsToValidate = function() {
|
|
|
3315
3314
|
return this.$__getValue(i);
|
|
3316
3315
|
}.bind(this))
|
|
3317
3316
|
.filter(function(val) {
|
|
3318
|
-
return val && val
|
|
3317
|
+
return val && Array.isArray(val) && utils.isMongooseDocumentArray(val) && val.length;
|
|
3319
3318
|
}).reduce(function(seed, array) {
|
|
3320
3319
|
return seed.concat(array);
|
|
3321
3320
|
}, [])
|
|
@@ -3357,12 +3356,12 @@ Document.prototype.$getAllSubdocs = function() {
|
|
|
3357
3356
|
seed = Array.from(val.keys()).reduce(function(seed, path) {
|
|
3358
3357
|
return docReducer(val.get(path), seed, null);
|
|
3359
3358
|
}, seed);
|
|
3360
|
-
} else if (val && val.$isSingleNested) {
|
|
3359
|
+
} else if (val && !Array.isArray(val) && val.$isSingleNested) {
|
|
3361
3360
|
seed = Object.keys(val._doc).reduce(function(seed, path) {
|
|
3362
3361
|
return docReducer(val._doc, seed, path);
|
|
3363
3362
|
}, seed);
|
|
3364
3363
|
seed.push(val);
|
|
3365
|
-
} else if (val &&
|
|
3364
|
+
} else if (val && utils.isMongooseDocumentArray(val)) {
|
|
3366
3365
|
val.forEach(function _docReduce(doc) {
|
|
3367
3366
|
if (!doc || !doc._doc) {
|
|
3368
3367
|
return;
|
|
@@ -3436,8 +3435,11 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3436
3435
|
};
|
|
3437
3436
|
|
|
3438
3437
|
const path = json ? 'toJSON' : 'toObject';
|
|
3439
|
-
const baseOptions =
|
|
3440
|
-
|
|
3438
|
+
const baseOptions = this.constructor &&
|
|
3439
|
+
this.constructor.base &&
|
|
3440
|
+
this.constructor.base.options &&
|
|
3441
|
+
get(this.constructor.base.options, path) || {};
|
|
3442
|
+
const schemaOptions = this.$__schema && this.$__schema.options || {};
|
|
3441
3443
|
// merge base default options with Schema's set default options if available.
|
|
3442
3444
|
// `clone` is necessary here because `utils.options` directly modifies the second input.
|
|
3443
3445
|
defaultOptions = utils.options(defaultOptions, clone(baseOptions));
|
|
@@ -3484,12 +3486,11 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3484
3486
|
}
|
|
3485
3487
|
|
|
3486
3488
|
const depopulate = options.depopulate ||
|
|
3487
|
-
|
|
3489
|
+
(options._parentOptions && options._parentOptions.depopulate || false);
|
|
3488
3490
|
// _isNested will only be true if this is not the top level document, we
|
|
3489
|
-
// should never depopulate
|
|
3491
|
+
// should never depopulate the top-level document
|
|
3490
3492
|
if (depopulate && options._isNested && this.$__.wasPopulated) {
|
|
3491
|
-
|
|
3492
|
-
return clone(this._id, cloneOptions);
|
|
3493
|
+
return clone(this.$__.wasPopulated.value || this._id, cloneOptions);
|
|
3493
3494
|
}
|
|
3494
3495
|
|
|
3495
3496
|
// merge default options with input options.
|
|
@@ -3564,7 +3565,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3564
3565
|
/**
|
|
3565
3566
|
* Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)).
|
|
3566
3567
|
*
|
|
3567
|
-
* Buffers are converted to instances of [mongodb.Binary](
|
|
3568
|
+
* Buffers are converted to instances of [mongodb.Binary](https://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html) for proper storage.
|
|
3568
3569
|
*
|
|
3569
3570
|
* ####Options:
|
|
3570
3571
|
*
|
|
@@ -3703,7 +3704,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3703
3704
|
* @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
|
|
3704
3705
|
* @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.
|
|
3705
3706
|
* @return {Object} js object
|
|
3706
|
-
* @see mongodb.Binary
|
|
3707
|
+
* @see mongodb.Binary https://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html
|
|
3707
3708
|
* @api public
|
|
3708
3709
|
* @memberOf Document
|
|
3709
3710
|
* @instance
|
|
@@ -3761,7 +3762,9 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
3761
3762
|
let assignPath;
|
|
3762
3763
|
let cur = self._doc;
|
|
3763
3764
|
let v;
|
|
3764
|
-
const aliases =
|
|
3765
|
+
const aliases = typeof (toObjectOptions && toObjectOptions.aliases) === 'boolean'
|
|
3766
|
+
? toObjectOptions.aliases
|
|
3767
|
+
: true;
|
|
3765
3768
|
|
|
3766
3769
|
let virtualsToApply = null;
|
|
3767
3770
|
if (Array.isArray(options.virtuals)) {
|
|
@@ -3955,15 +3958,20 @@ function omitDeselectedFields(self, json) {
|
|
|
3955
3958
|
}
|
|
3956
3959
|
|
|
3957
3960
|
/**
|
|
3958
|
-
* The return value of this method is used in calls to JSON.stringify(doc).
|
|
3961
|
+
* 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).
|
|
3959
3962
|
*
|
|
3960
3963
|
* 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.
|
|
3961
3964
|
*
|
|
3962
|
-
* schema.set('toJSON', { virtuals: true })
|
|
3965
|
+
* schema.set('toJSON', { virtuals: true });
|
|
3966
|
+
*
|
|
3967
|
+
* There is one difference between `toJSON()` and `toObject()` options.
|
|
3968
|
+
* 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.
|
|
3969
|
+
* When you call `toObject()`, the `flattenMaps` option is `false` by default.
|
|
3963
3970
|
*
|
|
3964
|
-
* See [schema options](/docs/guide.html#toJSON) for
|
|
3971
|
+
* See [schema options](/docs/guide.html#toJSON) for more information on setting `toJSON` option defaults.
|
|
3965
3972
|
*
|
|
3966
3973
|
* @param {Object} options
|
|
3974
|
+
* @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.
|
|
3967
3975
|
* @return {Object}
|
|
3968
3976
|
* @see Document#toObject #document_Document-toObject
|
|
3969
3977
|
* @see JSON.stringify() in JavaScript https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html
|
|
@@ -4118,6 +4126,7 @@ Document.prototype.equals = function(doc) {
|
|
|
4118
4126
|
* @param {Object} [match] Conditions for the population query
|
|
4119
4127
|
* @param {Object} [options] Options for the population query (sort, etc)
|
|
4120
4128
|
* @param {String} [options.path=null] The path to populate.
|
|
4129
|
+
* @param {string|PopulateOptions} [options.populate=null] Recursively populate paths in the populated documents. See [deep populate docs](/docs/populate.html#deep-populate).
|
|
4121
4130
|
* @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.
|
|
4122
4131
|
* @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).
|
|
4123
4132
|
* @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.
|
|
@@ -4139,7 +4148,7 @@ Document.prototype.populate = function populate() {
|
|
|
4139
4148
|
const args = [...arguments];
|
|
4140
4149
|
let fn;
|
|
4141
4150
|
|
|
4142
|
-
if (args.length
|
|
4151
|
+
if (args.length !== 0) {
|
|
4143
4152
|
if (typeof args[args.length - 1] === 'function') {
|
|
4144
4153
|
fn = args.pop();
|
|
4145
4154
|
}
|
|
@@ -4298,7 +4307,7 @@ Document.prototype.depopulate = function(path) {
|
|
|
4298
4307
|
|
|
4299
4308
|
let populatedIds;
|
|
4300
4309
|
const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
|
|
4301
|
-
const populated =
|
|
4310
|
+
const populated = this.$__ && this.$__.populated || {};
|
|
4302
4311
|
|
|
4303
4312
|
if (arguments.length === 0) {
|
|
4304
4313
|
// Depopulate all
|