mongoose 6.1.8 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +150 -0
- package/CHANGELOG.md +50 -0
- package/dist/browser.umd.js +191 -187
- package/lib/aggregate.js +1 -1
- package/lib/cast/objectid.js +1 -2
- package/lib/cast.js +21 -8
- package/lib/connection.js +33 -3
- package/lib/document.js +84 -65
- package/lib/error/index.js +11 -0
- package/lib/error/syncIndexes.js +30 -0
- package/lib/helpers/clone.js +40 -27
- package/lib/helpers/common.js +2 -2
- package/lib/helpers/getFunctionName.js +6 -4
- 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 +8 -4
- package/lib/helpers/populate/getModelsMapForPopulate.js +6 -6
- package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
- package/lib/helpers/populate/modelNamesFromRefPath.js +6 -5
- package/lib/helpers/query/cast$expr.js +284 -0
- package/lib/helpers/query/castUpdate.js +6 -2
- package/lib/helpers/schema/applyPlugins.js +11 -0
- package/lib/helpers/schema/getPath.js +4 -2
- package/lib/helpers/setDefaultsOnInsert.js +16 -7
- package/lib/helpers/timestamps/setupTimestamps.js +3 -8
- package/lib/helpers/update/applyTimestampsToChildren.js +2 -2
- package/lib/helpers/update/castArrayFilters.js +1 -1
- package/lib/helpers/update/updatedPathsByArrayFilter.js +1 -1
- package/lib/index.js +16 -40
- package/lib/internal.js +1 -1
- package/lib/model.js +37 -18
- package/lib/plugins/trackTransaction.js +4 -3
- package/lib/query.js +15 -13
- package/lib/queryhelpers.js +1 -1
- package/lib/schema/SubdocumentPath.js +1 -1
- package/lib/schema/array.js +18 -16
- package/lib/schema/documentarray.js +6 -9
- package/lib/schema/objectid.js +1 -1
- package/lib/schema.js +5 -4
- package/lib/schematype.js +74 -26
- package/lib/types/ArraySubdocument.js +2 -1
- package/lib/types/DocumentArray/index.js +9 -26
- package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
- package/lib/types/DocumentArray/methods/index.js +15 -3
- package/lib/types/array/index.js +21 -20
- package/lib/types/array/isMongooseArray.js +5 -0
- package/lib/types/array/methods/index.js +12 -12
- package/lib/utils.js +15 -8
- package/package.json +24 -156
- package/tools/repl.js +1 -1
- package/tsconfig.json +10 -0
- package/{index.d.ts → types/index.d.ts} +146 -86
|
@@ -153,7 +153,7 @@ function applyTimestampsToUpdateKey(schema, key, update, now) {
|
|
|
153
153
|
// Single nested is easy
|
|
154
154
|
update[parentPath + '.' + updatedAt] = now;
|
|
155
155
|
} else if (parentSchemaType.$isMongooseDocumentArray) {
|
|
156
|
-
let childPath = key.
|
|
156
|
+
let childPath = key.substring(parentPath.length + 1);
|
|
157
157
|
|
|
158
158
|
if (/^\d+$/.test(childPath)) {
|
|
159
159
|
update[parentPath + '.' + childPath][updatedAt] = now;
|
|
@@ -161,7 +161,7 @@ function applyTimestampsToUpdateKey(schema, key, update, now) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
const firstDot = childPath.indexOf('.');
|
|
164
|
-
childPath = firstDot !== -1 ? childPath.
|
|
164
|
+
childPath = firstDot !== -1 ? childPath.substring(0, firstDot) : childPath;
|
|
165
165
|
|
|
166
166
|
update[parentPath + '.' + childPath + '.' + updatedAt] = now;
|
|
167
167
|
}
|
|
@@ -51,7 +51,7 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
|
|
|
51
51
|
const dot = key.indexOf('.');
|
|
52
52
|
let filterPath = dot === -1 ?
|
|
53
53
|
updatedPathsByFilter[key] + '.0' :
|
|
54
|
-
updatedPathsByFilter[key.
|
|
54
|
+
updatedPathsByFilter[key.substring(0, dot)] + '.0' + key.substring(dot);
|
|
55
55
|
if (filterPath == null) {
|
|
56
56
|
throw new Error(`Filter path not found for ${key}`);
|
|
57
57
|
}
|
|
@@ -19,7 +19,7 @@ module.exports = function updatedPathsByArrayFilter(update) {
|
|
|
19
19
|
throw new Error(`Path '${path}' contains the same array filter multiple times`);
|
|
20
20
|
}
|
|
21
21
|
cur[match.substring(2, match.length - 1)] = path.
|
|
22
|
-
|
|
22
|
+
substring(0, firstMatch - 1).
|
|
23
23
|
replace(/\$\[[^\]]+\]/g, '0');
|
|
24
24
|
}
|
|
25
25
|
return cur;
|
package/lib/index.js
CHANGED
|
@@ -947,55 +947,31 @@ Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
|
|
|
947
947
|
*
|
|
948
948
|
* mongoose.isValidObjectId(new mongoose.Types.ObjectId()); // true
|
|
949
949
|
* mongoose.isValidObjectId('0123456789ab'); // true
|
|
950
|
-
* mongoose.isValidObjectId(6); //
|
|
950
|
+
* mongoose.isValidObjectId(6); // true
|
|
951
|
+
* mongoose.isValidObjectId({ test: 42 }); // false
|
|
951
952
|
*
|
|
952
953
|
* @method isValidObjectId
|
|
954
|
+
* @param {Any} value
|
|
955
|
+
* @returns {boolean} true if it is a valid ObjectId
|
|
953
956
|
* @api public
|
|
954
957
|
*/
|
|
955
958
|
|
|
956
959
|
Mongoose.prototype.isValidObjectId = function(v) {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
}
|
|
960
|
-
const base = this || mongoose;
|
|
961
|
-
const ObjectId = base.driver.get().ObjectId;
|
|
962
|
-
if (v instanceof ObjectId) {
|
|
963
|
-
return true;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
if (v._id != null) {
|
|
967
|
-
if (v._id instanceof ObjectId) {
|
|
968
|
-
return true;
|
|
969
|
-
}
|
|
970
|
-
if (v._id.toString instanceof Function) {
|
|
971
|
-
v = v._id.toString();
|
|
972
|
-
if (typeof v === 'string' && v.length === 12) {
|
|
973
|
-
return true;
|
|
974
|
-
}
|
|
975
|
-
if (typeof v === 'string' && /^[0-9A-Fa-f]{24}$/.test(v)) {
|
|
976
|
-
return true;
|
|
977
|
-
}
|
|
978
|
-
return false;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
if (v.toString instanceof Function) {
|
|
983
|
-
v = v.toString();
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
if (typeof v === 'string' && v.length === 12) {
|
|
987
|
-
return true;
|
|
988
|
-
}
|
|
989
|
-
if (typeof v === 'string' && /^[0-9A-Fa-f]{24}$/.test(v)) {
|
|
990
|
-
return true;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
return false;
|
|
960
|
+
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
961
|
+
return _mongoose.Types.ObjectId.isValid(v);
|
|
994
962
|
};
|
|
995
963
|
|
|
996
|
-
|
|
964
|
+
/**
|
|
965
|
+
*
|
|
966
|
+
* Syncs all the indexes for the models registered with this connection.
|
|
967
|
+
*
|
|
968
|
+
* @param {Object} options
|
|
969
|
+
* @param {Boolean} options.continueOnError `false` by default. If set to `true`, mongoose will not throw an error if one model syncing failed, and will return an object where the keys are the names of the models, and the values are the results/errors for each model.
|
|
970
|
+
* @returns
|
|
971
|
+
*/
|
|
972
|
+
Mongoose.prototype.syncIndexes = function(options) {
|
|
997
973
|
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
998
|
-
return _mongoose.connection.syncIndexes();
|
|
974
|
+
return _mongoose.connection.syncIndexes(options);
|
|
999
975
|
};
|
|
1000
976
|
|
|
1001
977
|
/**
|
package/lib/internal.js
CHANGED
|
@@ -10,7 +10,7 @@ const ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default', '
|
|
|
10
10
|
module.exports = exports = InternalCache;
|
|
11
11
|
|
|
12
12
|
function InternalCache() {
|
|
13
|
-
this.activePaths = new ActiveRoster;
|
|
13
|
+
this.activePaths = new ActiveRoster();
|
|
14
14
|
this.strictMode = undefined;
|
|
15
15
|
}
|
|
16
16
|
|
package/lib/model.js
CHANGED
|
@@ -48,6 +48,7 @@ const modifiedPaths = require('./helpers/update/modifiedPaths');
|
|
|
48
48
|
const parallelLimit = require('./helpers/parallelLimit');
|
|
49
49
|
const prepareDiscriminatorPipeline = require('./helpers/aggregate/prepareDiscriminatorPipeline');
|
|
50
50
|
const removeDeselectedForeignField = require('./helpers/populate/removeDeselectedForeignField');
|
|
51
|
+
const setDottedPath = require('./helpers/path/setDottedPath');
|
|
51
52
|
const util = require('util');
|
|
52
53
|
const utils = require('./utils');
|
|
53
54
|
|
|
@@ -379,7 +380,12 @@ Model.prototype.$__save = function(options, callback) {
|
|
|
379
380
|
});
|
|
380
381
|
}
|
|
381
382
|
let numAffected = 0;
|
|
382
|
-
|
|
383
|
+
const writeConcern = options != null ?
|
|
384
|
+
options.writeConcern != null ?
|
|
385
|
+
options.writeConcern.w :
|
|
386
|
+
options.w :
|
|
387
|
+
0;
|
|
388
|
+
if (writeConcern !== 0) {
|
|
383
389
|
// Skip checking if write succeeded if writeConcern is set to
|
|
384
390
|
// unacknowledged writes, because otherwise `numAffected` will always be 0
|
|
385
391
|
if (result != null) {
|
|
@@ -391,8 +397,10 @@ Model.prototype.$__save = function(options, callback) {
|
|
|
391
397
|
numAffected = result;
|
|
392
398
|
}
|
|
393
399
|
}
|
|
400
|
+
|
|
401
|
+
const versionBump = this.$__.version || this.$__schema.options.optimisticConcurrency;
|
|
394
402
|
// was this an update that required a version bump?
|
|
395
|
-
if (
|
|
403
|
+
if (versionBump && !this.$__.inserting) {
|
|
396
404
|
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
|
|
397
405
|
this.$__.version = undefined;
|
|
398
406
|
const key = this.$__schema.options.versionKey;
|
|
@@ -740,7 +748,7 @@ Model.prototype.$__delta = function() {
|
|
|
740
748
|
operand(this, where, delta, data, 1, '$unset');
|
|
741
749
|
} else if (value === null) {
|
|
742
750
|
operand(this, where, delta, data, null);
|
|
743
|
-
} else if (
|
|
751
|
+
} else if (utils.isMongooseArray(value) && value.$path() && value[arrayAtomicsSymbol]) {
|
|
744
752
|
// arrays and other custom types (support plugins etc)
|
|
745
753
|
handleAtomics(this, where, delta, data, value);
|
|
746
754
|
} else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
|
|
@@ -792,7 +800,7 @@ function checkDivergentArray(doc, path, array) {
|
|
|
792
800
|
}
|
|
793
801
|
}
|
|
794
802
|
|
|
795
|
-
if (!(pop &&
|
|
803
|
+
if (!(pop && utils.isMongooseArray(array))) return;
|
|
796
804
|
|
|
797
805
|
// If the array was populated using options that prevented all
|
|
798
806
|
// documents from being returned (match, skip, limit) or they
|
|
@@ -832,7 +840,8 @@ Model.prototype.$__version = function(where, delta) {
|
|
|
832
840
|
if (where === true) {
|
|
833
841
|
// this is an insert
|
|
834
842
|
if (key) {
|
|
835
|
-
|
|
843
|
+
setDottedPath(delta, key, 0);
|
|
844
|
+
this.$__setValue(key, 0);
|
|
836
845
|
}
|
|
837
846
|
return;
|
|
838
847
|
}
|
|
@@ -1059,8 +1068,8 @@ Model.prototype.model = function model(name) {
|
|
|
1059
1068
|
};
|
|
1060
1069
|
|
|
1061
1070
|
/**
|
|
1062
|
-
* Returns
|
|
1063
|
-
* the given `filter`, and
|
|
1071
|
+
* Returns a document with `_id` only if at least one document exists in the database that matches
|
|
1072
|
+
* the given `filter`, and `null` otherwise.
|
|
1064
1073
|
*
|
|
1065
1074
|
* Under the hood, `MyModel.exists({ answer: 42 })` is equivalent to
|
|
1066
1075
|
* `MyModel.findOne({ answer: 42 }).select({ _id: 1 }).lean()`
|
|
@@ -1097,10 +1106,6 @@ Model.exists = function exists(filter, options, callback) {
|
|
|
1097
1106
|
if (typeof callback === 'function') {
|
|
1098
1107
|
return query.exec(callback);
|
|
1099
1108
|
}
|
|
1100
|
-
options = options || {};
|
|
1101
|
-
if (!options.explain) {
|
|
1102
|
-
return query.then(doc => !!doc);
|
|
1103
|
-
}
|
|
1104
1109
|
|
|
1105
1110
|
return query;
|
|
1106
1111
|
};
|
|
@@ -1136,11 +1141,13 @@ Model.exists = function exists(filter, options, callback) {
|
|
|
1136
1141
|
* @param {Object|String} [options] If string, same as `options.value`.
|
|
1137
1142
|
* @param {String} [options.value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
|
|
1138
1143
|
* @param {Boolean} [options.clone=true] By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning.
|
|
1144
|
+
* @param {Boolean} [options.overwriteModels=false] by default, Mongoose does not allow you to define a discriminator with the same name as another discriminator. Set this to allow overwriting discriminators with the same name.
|
|
1139
1145
|
* @return {Model} The newly created discriminator model
|
|
1140
1146
|
* @api public
|
|
1141
1147
|
*/
|
|
1142
1148
|
|
|
1143
1149
|
Model.discriminator = function(name, schema, options) {
|
|
1150
|
+
|
|
1144
1151
|
let model;
|
|
1145
1152
|
if (typeof name === 'function') {
|
|
1146
1153
|
model = name;
|
|
@@ -1164,7 +1171,7 @@ Model.discriminator = function(name, schema, options) {
|
|
|
1164
1171
|
}
|
|
1165
1172
|
|
|
1166
1173
|
schema = discriminator(this, name, schema, value, true);
|
|
1167
|
-
if (this.db.models[name]) {
|
|
1174
|
+
if (this.db.models[name] && !schema.options.overwriteModels) {
|
|
1168
1175
|
throw new OverwriteModelError(name);
|
|
1169
1176
|
}
|
|
1170
1177
|
|
|
@@ -3374,7 +3381,7 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3374
3381
|
return doc != null;
|
|
3375
3382
|
});
|
|
3376
3383
|
// Quickly escape while there aren't any valid docAttributes
|
|
3377
|
-
if (docAttributes.length
|
|
3384
|
+
if (docAttributes.length === 0) {
|
|
3378
3385
|
if (rawResult) {
|
|
3379
3386
|
const res = {
|
|
3380
3387
|
mongoose: {
|
|
@@ -3609,16 +3616,21 @@ Model.bulkWrite = function(ops, options, callback) {
|
|
|
3609
3616
|
* `bulkSave` uses `bulkWrite` under the hood, so it's mostly useful when dealing with many documents (10K+)
|
|
3610
3617
|
*
|
|
3611
3618
|
* @param {[Document]} documents
|
|
3619
|
+
* @param {Object} [options] options passed to the underlying `bulkWrite()`
|
|
3620
|
+
* @param {ClientSession} [options.session=null] The session associated with this bulk write. See [transactions docs](/docs/transactions.html).
|
|
3621
|
+
* @param {String|number} [options.w=1] The [write concern](https://docs.mongodb.com/manual/reference/write-concern/). See [`Query#w()`](/docs/api.html#query_Query-w) for more information.
|
|
3622
|
+
* @param {number} [options.wtimeout=null] The [write concern timeout](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout).
|
|
3623
|
+
* @param {Boolean} [options.j=true] If false, disable [journal acknowledgement](https://docs.mongodb.com/manual/reference/write-concern/#j-option)
|
|
3612
3624
|
*
|
|
3613
3625
|
*/
|
|
3614
|
-
Model.bulkSave = function(documents) {
|
|
3626
|
+
Model.bulkSave = function(documents, options) {
|
|
3615
3627
|
const preSavePromises = documents.map(buildPreSavePromise);
|
|
3616
3628
|
|
|
3617
3629
|
const writeOperations = this.buildBulkWriteOperations(documents, { skipValidation: true });
|
|
3618
3630
|
|
|
3619
3631
|
let bulkWriteResultPromise;
|
|
3620
3632
|
return Promise.all(preSavePromises)
|
|
3621
|
-
.then(() => bulkWriteResultPromise = this.bulkWrite(writeOperations))
|
|
3633
|
+
.then(() => bulkWriteResultPromise = this.bulkWrite(writeOperations, options))
|
|
3622
3634
|
.then(() => documents.map(buildSuccessfulWriteHandlerPromise))
|
|
3623
3635
|
.then(() => bulkWriteResultPromise)
|
|
3624
3636
|
.catch((err) => {
|
|
@@ -4451,9 +4463,16 @@ const excludeIdRegGlobal = /\s?-_id\s?/g;
|
|
|
4451
4463
|
|
|
4452
4464
|
function populate(model, docs, options, callback) {
|
|
4453
4465
|
const populateOptions = { ...options };
|
|
4454
|
-
if (
|
|
4455
|
-
|
|
4466
|
+
if (options.strictPopulate == null) {
|
|
4467
|
+
if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) {
|
|
4468
|
+
populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate;
|
|
4469
|
+
} else if (options._localModel != null && model.base.options.strictPopulate != null) {
|
|
4470
|
+
populateOptions.strictPopulate = model.base.options.strictPopulate;
|
|
4471
|
+
} else if (model.base.options.strictPopulate != null) {
|
|
4472
|
+
populateOptions.strictPopulate = model.base.options.strictPopulate;
|
|
4473
|
+
}
|
|
4456
4474
|
}
|
|
4475
|
+
|
|
4457
4476
|
// normalize single / multiple docs passed
|
|
4458
4477
|
if (!Array.isArray(docs)) {
|
|
4459
4478
|
docs = [docs];
|
|
@@ -4524,7 +4543,7 @@ function populate(model, docs, options, callback) {
|
|
|
4524
4543
|
}
|
|
4525
4544
|
if (!hasOne) {
|
|
4526
4545
|
// If models but no docs, skip further deep populate.
|
|
4527
|
-
if (modelsMap.length
|
|
4546
|
+
if (modelsMap.length !== 0) {
|
|
4528
4547
|
return callback();
|
|
4529
4548
|
}
|
|
4530
4549
|
// If no models to populate but we have a nested populate,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const arrayAtomicsSymbol = require('../helpers/symbols').arrayAtomicsSymbol;
|
|
4
4
|
const sessionNewDocuments = require('../helpers/symbols').sessionNewDocuments;
|
|
5
|
+
const utils = require('../utils');
|
|
5
6
|
|
|
6
7
|
module.exports = function trackTransaction(schema) {
|
|
7
8
|
schema.pre('save', function() {
|
|
@@ -47,10 +48,10 @@ function _getAtomics(doc, previous) {
|
|
|
47
48
|
const val = doc.$__getValue(path);
|
|
48
49
|
if (val != null &&
|
|
49
50
|
val instanceof Array &&
|
|
50
|
-
|
|
51
|
+
utils.isMongooseDocumentArray(val) &&
|
|
51
52
|
val.length &&
|
|
52
53
|
val[arrayAtomicsSymbol] != null &&
|
|
53
|
-
Object.keys(val[arrayAtomicsSymbol]).length
|
|
54
|
+
Object.keys(val[arrayAtomicsSymbol]).length !== 0) {
|
|
54
55
|
const existing = previous.get(path) || {};
|
|
55
56
|
pathToAtomics.set(path, mergeAtomics(existing, val[arrayAtomicsSymbol]));
|
|
56
57
|
}
|
|
@@ -61,7 +62,7 @@ function _getAtomics(doc, previous) {
|
|
|
61
62
|
const path = dirt.path;
|
|
62
63
|
|
|
63
64
|
const val = dirt.value;
|
|
64
|
-
if (val != null && val[arrayAtomicsSymbol] != null && Object.keys(val[arrayAtomicsSymbol]).length
|
|
65
|
+
if (val != null && val[arrayAtomicsSymbol] != null && Object.keys(val[arrayAtomicsSymbol]).length !== 0) {
|
|
65
66
|
const existing = previous.get(path) || {};
|
|
66
67
|
pathToAtomics.set(path, mergeAtomics(existing, val[arrayAtomicsSymbol]));
|
|
67
68
|
}
|
package/lib/query.js
CHANGED
|
@@ -120,7 +120,7 @@ function Query(conditions, options, model, collection) {
|
|
|
120
120
|
* inherit mquery
|
|
121
121
|
*/
|
|
122
122
|
|
|
123
|
-
Query.prototype = new mquery;
|
|
123
|
+
Query.prototype = new mquery();
|
|
124
124
|
Query.prototype.constructor = Query;
|
|
125
125
|
Query.base = mquery.prototype;
|
|
126
126
|
|
|
@@ -4848,7 +4848,8 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
|
|
|
4848
4848
|
overwrite: overwrite,
|
|
4849
4849
|
strict: this._mongooseOptions.strict,
|
|
4850
4850
|
upsert: upsert,
|
|
4851
|
-
arrayFilters: this.options.arrayFilters
|
|
4851
|
+
arrayFilters: this.options.arrayFilters,
|
|
4852
|
+
overwriteDiscriminatorKey: this._mongooseOptions.overwriteDiscriminatorKey
|
|
4852
4853
|
}, this, this._conditions);
|
|
4853
4854
|
};
|
|
4854
4855
|
|
|
@@ -5057,18 +5058,19 @@ Query.prototype.cast = function(model, obj) {
|
|
|
5057
5058
|
model = getDiscriminatorByValue(model.discriminators, obj[discriminatorKey]) || model;
|
|
5058
5059
|
}
|
|
5059
5060
|
|
|
5061
|
+
const opts = { upsert: this.options && this.options.upsert };
|
|
5062
|
+
if (this.options) {
|
|
5063
|
+
if ('strict' in this.options) {
|
|
5064
|
+
opts.strict = this.options.strict;
|
|
5065
|
+
opts.strictQuery = opts.strict;
|
|
5066
|
+
}
|
|
5067
|
+
if ('strictQuery' in this.options) {
|
|
5068
|
+
opts.strictQuery = this.options.strictQuery;
|
|
5069
|
+
}
|
|
5070
|
+
}
|
|
5071
|
+
|
|
5060
5072
|
try {
|
|
5061
|
-
return cast(model.schema, obj,
|
|
5062
|
-
upsert: this.options && this.options.upsert,
|
|
5063
|
-
strict: (this.options && 'strict' in this.options) ?
|
|
5064
|
-
this.options.strict :
|
|
5065
|
-
get(model, 'schema.options.strict', null),
|
|
5066
|
-
strictQuery: (this.options && 'strictQuery' in this.options) ?
|
|
5067
|
-
this.options.strictQuery :
|
|
5068
|
-
(this.options && 'strict' in this.options) ?
|
|
5069
|
-
this.options.strict :
|
|
5070
|
-
get(model, 'schema.options.strictQuery', null)
|
|
5071
|
-
}, this);
|
|
5073
|
+
return cast(model.schema, obj, opts, this);
|
|
5072
5074
|
} catch (err) {
|
|
5073
5075
|
// CastError, assign model
|
|
5074
5076
|
if (typeof err.setModel === 'function') {
|
package/lib/queryhelpers.js
CHANGED
|
@@ -212,7 +212,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
212
212
|
|
|
213
213
|
let addedPath = analyzePath(path, type);
|
|
214
214
|
// arrays
|
|
215
|
-
if (addedPath == null && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
|
|
215
|
+
if (addedPath == null && !Array.isArray(type) && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
|
|
216
216
|
addedPath = analyzePath(path, type.caster);
|
|
217
217
|
}
|
|
218
218
|
if (addedPath != null) {
|
|
@@ -168,7 +168,7 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) {
|
|
|
168
168
|
const path = this.path;
|
|
169
169
|
const selected = Object.keys(parentSelected).reduce((obj, key) => {
|
|
170
170
|
if (key.startsWith(path + '.')) {
|
|
171
|
-
obj[key.
|
|
171
|
+
obj[key.substring(path.length + 1)] = parentSelected[key];
|
|
172
172
|
}
|
|
173
173
|
return obj;
|
|
174
174
|
}, {});
|
package/lib/schema/array.js
CHANGED
|
@@ -112,14 +112,12 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
|
|
112
112
|
|
|
113
113
|
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
|
|
114
114
|
const defaultFn = function() {
|
|
115
|
-
let arr = [];
|
|
116
|
-
if (fn) {
|
|
117
|
-
arr = defaultArr.call(this);
|
|
118
|
-
} else if (defaultArr != null) {
|
|
119
|
-
arr = arr.concat(defaultArr);
|
|
120
|
-
}
|
|
121
115
|
// Leave it up to `cast()` to convert the array
|
|
122
|
-
return
|
|
116
|
+
return fn
|
|
117
|
+
? defaultArr.call(this)
|
|
118
|
+
: defaultArr != null
|
|
119
|
+
? [].concat(defaultArr)
|
|
120
|
+
: [];
|
|
123
121
|
};
|
|
124
122
|
defaultFn.$runBeforeSetters = !fn;
|
|
125
123
|
this.default(defaultFn);
|
|
@@ -275,7 +273,7 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
|
|
|
275
273
|
|
|
276
274
|
const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
|
|
277
275
|
if (Array.isArray(ret)) {
|
|
278
|
-
const rawValue = ret
|
|
276
|
+
const rawValue = utils.isMongooseArray(ret) ? ret.__array : ret;
|
|
279
277
|
const len = rawValue.length;
|
|
280
278
|
for (let i = 0; i < len; ++i) {
|
|
281
279
|
rawValue[i] = this.caster.applyGetters(rawValue[i], scope);
|
|
@@ -299,7 +297,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
|
|
|
299
297
|
}
|
|
300
298
|
|
|
301
299
|
// No need to wrap empty arrays
|
|
302
|
-
if (value != null && value.length
|
|
300
|
+
if (value != null && value.length !== 0) {
|
|
303
301
|
const valueDepth = arrayDepth(value);
|
|
304
302
|
if (valueDepth.min === valueDepth.max && valueDepth.max < depth && valueDepth.containsNonArrayItem) {
|
|
305
303
|
for (let i = valueDepth.max; i < depth; ++i) {
|
|
@@ -344,7 +342,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
344
342
|
// Special case: if this index is on the parent of what looks like
|
|
345
343
|
// GeoJSON, skip setting the default to empty array re: #1668, #3233
|
|
346
344
|
const arrayGeojsonPath = this.path.endsWith('.coordinates') ?
|
|
347
|
-
this.path.
|
|
345
|
+
this.path.substring(0, this.path.lastIndexOf('.')) : null;
|
|
348
346
|
if (arrayGeojsonPath != null) {
|
|
349
347
|
for (i = 0, l = indexes.length; i < l; ++i) {
|
|
350
348
|
const pathIndex = indexes[i][0][arrayGeojsonPath];
|
|
@@ -357,7 +355,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
357
355
|
|
|
358
356
|
options = options || emptyOpts;
|
|
359
357
|
|
|
360
|
-
let rawValue = value
|
|
358
|
+
let rawValue = utils.isMongooseArray(value) ? value.__array : value;
|
|
361
359
|
value = MongooseArray(rawValue, options.path || this._arrayPath || this.path, doc, this);
|
|
362
360
|
rawValue = value.__array;
|
|
363
361
|
|
|
@@ -557,12 +555,16 @@ function cast$all(val) {
|
|
|
557
555
|
}
|
|
558
556
|
|
|
559
557
|
val = val.map(function(v) {
|
|
560
|
-
if (utils.isObject(v)) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
558
|
+
if (!utils.isObject(v)) {
|
|
559
|
+
return v;
|
|
560
|
+
}
|
|
561
|
+
if (v.$elemMatch != null) {
|
|
562
|
+
return { $elemMatch: cast(this.casterConstructor.schema, v.$elemMatch) };
|
|
564
563
|
}
|
|
565
|
-
|
|
564
|
+
|
|
565
|
+
const o = {};
|
|
566
|
+
o[this.path] = v;
|
|
567
|
+
return cast(this.casterConstructor.schema, o)[this.path];
|
|
566
568
|
}, this);
|
|
567
569
|
|
|
568
570
|
return this.castForQuery(val);
|
|
@@ -228,7 +228,7 @@ DocumentArrayPath.prototype.doValidate = function(array, fn, scope, options) {
|
|
|
228
228
|
if (options && options.updateValidator) {
|
|
229
229
|
return fn();
|
|
230
230
|
}
|
|
231
|
-
if (!
|
|
231
|
+
if (!utils.isMongooseDocumentArray(array)) {
|
|
232
232
|
array = new MongooseDocumentArray(array, _this.path, scope);
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -398,12 +398,9 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
398
398
|
return this.cast([value], doc, init, prev, options);
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
} else if (value && value.isMongooseDocumentArray) {
|
|
405
|
-
// We need to create a new array, otherwise change tracking will
|
|
406
|
-
// update the old doc (gh-4449)
|
|
401
|
+
// We need to create a new array, otherwise change tracking will
|
|
402
|
+
// update the old doc (gh-4449)
|
|
403
|
+
if (!options.skipDocumentArrayCast || utils.isMongooseDocumentArray(value)) {
|
|
407
404
|
value = new MongooseDocumentArray(value, this.path, doc);
|
|
408
405
|
}
|
|
409
406
|
|
|
@@ -415,7 +412,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
415
412
|
value[arrayPathSymbol] = this.path + '.' + options.arrayPathIndex;
|
|
416
413
|
}
|
|
417
414
|
|
|
418
|
-
const rawArray = value
|
|
415
|
+
const rawArray = utils.isMongooseDocumentArray(value) ? value.__array : value;
|
|
419
416
|
|
|
420
417
|
const len = rawArray.length;
|
|
421
418
|
const initDocumentOptions = { skipId: true, willInit: true };
|
|
@@ -546,7 +543,7 @@ function scopePaths(array, fields, init) {
|
|
|
546
543
|
continue;
|
|
547
544
|
}
|
|
548
545
|
if (sub.startsWith('$.')) {
|
|
549
|
-
sub = sub.
|
|
546
|
+
sub = sub.substring(2);
|
|
550
547
|
}
|
|
551
548
|
hasKeys || (hasKeys = true);
|
|
552
549
|
selected[sub] = fields[key];
|
package/lib/schema/objectid.js
CHANGED
package/lib/schema.js
CHANGED
|
@@ -75,6 +75,7 @@ let id = 0;
|
|
|
75
75
|
* - [selectPopulatedPaths](/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
|
|
76
76
|
* - [skipVersioning](/docs/guide.html#skipVersioning): object - paths to exclude from versioning
|
|
77
77
|
* - [timestamps](/docs/guide.html#timestamps): object or boolean - defaults to `false`. If true, Mongoose adds `createdAt` and `updatedAt` properties to your schema and manages those properties for you.
|
|
78
|
+
* - [pluginTags](/docs/guide.html#pluginTags): array of strings - defaults to `undefined`. If set and plugin called with `tags` option, will only apply that plugin to schemas with a matching tag.
|
|
78
79
|
*
|
|
79
80
|
* ####Options for Nested Schemas:
|
|
80
81
|
* - `excludeIndexes`: bool - defaults to `false`. If `true`, skip building indexes on this schema's paths.
|
|
@@ -532,13 +533,13 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
532
533
|
// Special-case: Non-options definitely a path so leaf at this node
|
|
533
534
|
// Examples: Schema instances, SchemaType instances
|
|
534
535
|
if (prefix) {
|
|
535
|
-
this.nested[prefix.
|
|
536
|
+
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
536
537
|
}
|
|
537
538
|
this.path(prefix + key, val);
|
|
538
539
|
} else if (Object.keys(val).length < 1) {
|
|
539
540
|
// Special-case: {} always interpreted as Mixed path so leaf at this node
|
|
540
541
|
if (prefix) {
|
|
541
|
-
this.nested[prefix.
|
|
542
|
+
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
542
543
|
}
|
|
543
544
|
this.path(fullPath, val); // mixed type
|
|
544
545
|
} else if (!val[typeKey] || (typeKey === 'type' && isPOJO(val.type) && val.type.type)) {
|
|
@@ -553,7 +554,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
553
554
|
if (isPOJO(_typeDef) && Object.keys(_typeDef).length > 0) {
|
|
554
555
|
// If a POJO is the value of a type key, make it a subdocument
|
|
555
556
|
if (prefix) {
|
|
556
|
-
this.nested[prefix.
|
|
557
|
+
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
557
558
|
}
|
|
558
559
|
const _schema = new Schema(_typeDef);
|
|
559
560
|
const schemaWrappedPath = Object.assign({}, val, { type: _schema });
|
|
@@ -561,7 +562,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
561
562
|
} else {
|
|
562
563
|
// Either the type is non-POJO or we interpret it as Mixed anyway
|
|
563
564
|
if (prefix) {
|
|
564
|
-
this.nested[prefix.
|
|
565
|
+
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
565
566
|
}
|
|
566
567
|
this.path(prefix + key, val);
|
|
567
568
|
}
|