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.
Files changed (55) hide show
  1. package/.eslintrc.json +150 -0
  2. package/CHANGELOG.md +50 -0
  3. package/dist/browser.umd.js +191 -187
  4. package/lib/aggregate.js +1 -1
  5. package/lib/cast/objectid.js +1 -2
  6. package/lib/cast.js +21 -8
  7. package/lib/connection.js +33 -3
  8. package/lib/document.js +84 -65
  9. package/lib/error/index.js +11 -0
  10. package/lib/error/syncIndexes.js +30 -0
  11. package/lib/helpers/clone.js +40 -27
  12. package/lib/helpers/common.js +2 -2
  13. package/lib/helpers/getFunctionName.js +6 -4
  14. package/lib/helpers/isMongooseObject.js +9 -8
  15. package/lib/helpers/isObject.js +4 -4
  16. package/lib/helpers/model/discriminator.js +2 -1
  17. package/lib/helpers/path/parentPaths.js +10 -5
  18. package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
  19. package/lib/helpers/populate/assignVals.js +8 -4
  20. package/lib/helpers/populate/getModelsMapForPopulate.js +6 -6
  21. package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
  22. package/lib/helpers/populate/modelNamesFromRefPath.js +6 -5
  23. package/lib/helpers/query/cast$expr.js +284 -0
  24. package/lib/helpers/query/castUpdate.js +6 -2
  25. package/lib/helpers/schema/applyPlugins.js +11 -0
  26. package/lib/helpers/schema/getPath.js +4 -2
  27. package/lib/helpers/setDefaultsOnInsert.js +16 -7
  28. package/lib/helpers/timestamps/setupTimestamps.js +3 -8
  29. package/lib/helpers/update/applyTimestampsToChildren.js +2 -2
  30. package/lib/helpers/update/castArrayFilters.js +1 -1
  31. package/lib/helpers/update/updatedPathsByArrayFilter.js +1 -1
  32. package/lib/index.js +16 -40
  33. package/lib/internal.js +1 -1
  34. package/lib/model.js +37 -18
  35. package/lib/plugins/trackTransaction.js +4 -3
  36. package/lib/query.js +15 -13
  37. package/lib/queryhelpers.js +1 -1
  38. package/lib/schema/SubdocumentPath.js +1 -1
  39. package/lib/schema/array.js +18 -16
  40. package/lib/schema/documentarray.js +6 -9
  41. package/lib/schema/objectid.js +1 -1
  42. package/lib/schema.js +5 -4
  43. package/lib/schematype.js +74 -26
  44. package/lib/types/ArraySubdocument.js +2 -1
  45. package/lib/types/DocumentArray/index.js +9 -26
  46. package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
  47. package/lib/types/DocumentArray/methods/index.js +15 -3
  48. package/lib/types/array/index.js +21 -20
  49. package/lib/types/array/isMongooseArray.js +5 -0
  50. package/lib/types/array/methods/index.js +12 -12
  51. package/lib/utils.js +15 -8
  52. package/package.json +24 -156
  53. package/tools/repl.js +1 -1
  54. package/tsconfig.json +10 -0
  55. package/{index.d.ts → types/index.d.ts} +146 -86
package/lib/aggregate.js CHANGED
@@ -39,7 +39,7 @@ const readConcern = Query.prototype.readConcern;
39
39
  * ```javascript
40
40
  * new Aggregate([{ $match: { _id: '00000000000000000000000a' } }]);
41
41
  * // Do this instead to cast to an ObjectId
42
- * new Aggregate([{ $match: { _id: mongoose.Types.ObjectId('00000000000000000000000a') } }]);
42
+ * new Aggregate([{ $match: { _id: new mongoose.Types.ObjectId('00000000000000000000000a') } }]);
43
43
  * ```
44
44
  *
45
45
  * @see MongoDB http://docs.mongodb.org/manual/applications/aggregation/
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const ObjectId = require('../driver').get().ObjectId;
4
- const assert = require('assert');
5
4
 
6
5
  module.exports = function castObjectId(value) {
7
6
  if (value == null) {
@@ -25,5 +24,5 @@ module.exports = function castObjectId(value) {
25
24
  return new ObjectId(value.toString());
26
25
  }
27
26
 
28
- assert.ok(false);
27
+ return new ObjectId(value);
29
28
  };
package/lib/cast.js CHANGED
@@ -7,6 +7,7 @@
7
7
  const CastError = require('./error/cast');
8
8
  const StrictModeError = require('./error/strict');
9
9
  const Types = require('./schema/index');
10
+ const cast$expr = require('./helpers/query/cast$expr');
10
11
  const castTextSearch = require('./schema/operators/text');
11
12
  const get = require('./helpers/get');
12
13
  const getConstructorName = require('./helpers/getConstructorName');
@@ -79,9 +80,7 @@ module.exports = function cast(schema, obj, options, context) {
79
80
 
80
81
  continue;
81
82
  } else if (path === '$expr') {
82
- if (typeof val !== 'object' || val == null) {
83
- throw new Error('`$expr` must be an object');
84
- }
83
+ val = cast$expr(val, schema);
85
84
  continue;
86
85
  } else if (path === '$elemMatch') {
87
86
  val = cast(schema, val, options, context);
@@ -145,7 +144,13 @@ module.exports = function cast(schema, obj, options, context) {
145
144
  remainingConds = {};
146
145
  pathLastHalf = split.slice(j).join('.');
147
146
  remainingConds[pathLastHalf] = val;
148
- obj[path] = cast(schematype.caster.schema, remainingConds, options, context)[pathLastHalf];
147
+
148
+ const ret = cast(schematype.caster.schema, remainingConds, options, context)[pathLastHalf];
149
+ if (ret === void 0) {
150
+ delete obj[path];
151
+ } else {
152
+ obj[path] = ret;
153
+ }
149
154
  } else {
150
155
  obj[path] = val;
151
156
  }
@@ -251,16 +256,24 @@ module.exports = function cast(schema, obj, options, context) {
251
256
  if (schema.nested[path]) {
252
257
  continue;
253
258
  }
254
- if (options.upsert && options.strict) {
255
- if (options.strict === 'throw') {
259
+
260
+ const strict = 'strict' in options ? options.strict : schema.options.strict;
261
+ const strictQuery = 'strictQuery' in options ?
262
+ options.strictQuery :
263
+ 'strict' in options ?
264
+ options.strict :
265
+ 'strict' in schema._userProvidedOptions ? schema._userProvidedOptions.strict :
266
+ schema.options.strictQuery;
267
+ if (options.upsert && strict) {
268
+ if (strict === 'throw') {
256
269
  throw new StrictModeError(path);
257
270
  }
258
271
  throw new StrictModeError(path, 'Path "' + path + '" is not in ' +
259
272
  'schema, strict mode is `true`, and upsert is `true`.');
260
- } if (options.strictQuery === 'throw') {
273
+ } if (strictQuery === 'throw') {
261
274
  throw new StrictModeError(path, 'Path "' + path + '" is not in ' +
262
275
  'schema and strictQuery is \'throw\'.');
263
- } else if (options.strictQuery) {
276
+ } else if (strictQuery) {
264
277
  delete obj[path];
265
278
  }
266
279
  } else if (val == null) {
package/lib/connection.js CHANGED
@@ -10,6 +10,7 @@ const Schema = require('./schema');
10
10
  const Collection = require('./driver').get().Collection;
11
11
  const STATES = require('./connectionstate');
12
12
  const MongooseError = require('./error/index');
13
+ const SyncIndexesError = require('./error/syncIndexes');
13
14
  const PromiseProvider = require('./promise_provider');
14
15
  const ServerSelectionError = require('./error/serverSelection');
15
16
  const applyPlugins = require('./helpers/schema/applyPlugins');
@@ -1380,11 +1381,40 @@ Connection.prototype.setClient = function setClient(client) {
1380
1381
  return this;
1381
1382
  };
1382
1383
 
1383
- Connection.prototype.syncIndexes = async function syncIndexes() {
1384
+ /**
1385
+ *
1386
+ * Syncs all the indexes for the models registered with this connection.
1387
+ *
1388
+ * @param {Object} options
1389
+ * @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.
1390
+ * @returns
1391
+ */
1392
+ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
1384
1393
  const result = {};
1385
- for (const model in this.models) {
1386
- result[model] = await this.model(model).syncIndexes();
1394
+ const errorsMap = { };
1395
+
1396
+ const { continueOnError } = options;
1397
+ delete options.continueOnError;
1398
+
1399
+ for (const model of Object.values(this.models)) {
1400
+ try {
1401
+ result[model.modelName] = await model.syncIndexes(options);
1402
+ } catch (err) {
1403
+ if (!continueOnError) {
1404
+ errorsMap[model.modelName] = err;
1405
+ break;
1406
+ } else {
1407
+ result[model.modelName] = err;
1408
+ }
1409
+ }
1387
1410
  }
1411
+
1412
+ if (!continueOnError && Object.keys(errorsMap).length) {
1413
+ const message = Object.entries(errorsMap).map(([modelName, err]) => `${modelName}: ${err.message}`).join(', ');
1414
+ const syncIndexesError = new SyncIndexesError(message, errorsMap);
1415
+ throw syncIndexesError;
1416
+ }
1417
+
1388
1418
  return result;
1389
1419
  };
1390
1420
 
package/lib/document.js CHANGED
@@ -90,7 +90,7 @@ function Document(obj, fields, skipId, options) {
90
90
  options = arguments[4] || {};
91
91
  }
92
92
 
93
- this.$__ = new InternalCache;
93
+ this.$__ = new InternalCache();
94
94
  this.$isNew = 'isNew' in options ? options.isNew : true;
95
95
 
96
96
  if ('priorDoc' in options) {
@@ -479,7 +479,7 @@ function $__applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSet
479
479
  break;
480
480
  }
481
481
  } else if (exclude === false && fields && !included) {
482
- if (curPath in fields) {
482
+ if (curPath in fields || type.$isSingleNested && hasIncludedChildren[curPath]) {
483
483
  included = true;
484
484
  } else if (!hasIncludedChildren[curPath]) {
485
485
  break;
@@ -795,11 +795,12 @@ function init(self, obj, doc, opts, prefix) {
795
795
 
796
796
  const keys = Object.keys(obj);
797
797
  const len = keys.length;
798
- let schema;
798
+ let schemaType;
799
799
  let path;
800
800
  let i;
801
801
  let index = 0;
802
802
  const strict = self.$__.strictMode;
803
+ const docSchema = self.$__schema;
803
804
 
804
805
  while (index < len) {
805
806
  _init(index++);
@@ -808,25 +809,27 @@ function init(self, obj, doc, opts, prefix) {
808
809
  function _init(index) {
809
810
  i = keys[index];
810
811
  path = prefix + i;
811
- schema = self.$__schema.path(path);
812
+ schemaType = docSchema.path(path);
812
813
 
813
814
  // Should still work if not a model-level discriminator, but should not be
814
815
  // necessary. This is *only* to catch the case where we queried using the
815
816
  // base model and the discriminated model has a projection
816
- if (self.$__schema.$isRootDiscriminator && !self.$__isSelected(path)) {
817
+ if (docSchema.$isRootDiscriminator && !self.$__isSelected(path)) {
817
818
  return;
818
819
  }
819
820
 
820
- if (!schema && utils.isPOJO(obj[i])) {
821
+ if (!schemaType && utils.isPOJO(obj[i])) {
821
822
  // assume nested object
822
823
  if (!doc[i]) {
823
824
  doc[i] = {};
825
+ if (!strict && !(i in docSchema.tree) && !(i in docSchema.methods) && !(i in docSchema.virtuals)) {
826
+ self[i] = doc[i];
827
+ }
824
828
  }
825
829
  init(self, obj[i], doc[i], opts, path + '.');
826
- } else if (!schema) {
830
+ } else if (!schemaType) {
827
831
  doc[i] = obj[i];
828
- if (!strict && !prefix) {
829
- // Set top-level properties that aren't in the schema if strict is false
832
+ if (!strict) {
830
833
  self[i] = obj[i];
831
834
  }
832
835
  } else {
@@ -835,13 +838,13 @@ function init(self, obj, doc, opts, prefix) {
835
838
  delete doc[i];
836
839
  }
837
840
  if (obj[i] === null) {
838
- doc[i] = schema._castNullish(null);
841
+ doc[i] = schemaType._castNullish(null);
839
842
  } else if (obj[i] !== undefined) {
840
843
  const wasPopulated = obj[i].$__ == null ? null : obj[i].$__.wasPopulated;
841
844
 
842
- if (schema && !wasPopulated) {
845
+ if (schemaType && !wasPopulated) {
843
846
  try {
844
- doc[i] = schema.cast(obj[i], self, true);
847
+ doc[i] = schemaType.cast(obj[i], self, true);
845
848
  } catch (e) {
846
849
  self.invalidate(e.path, new ValidatorError({
847
850
  path: e.path,
@@ -1135,7 +1138,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1135
1138
  // them to ensure we keep the user's key order.
1136
1139
  if (type === true &&
1137
1140
  !prefix &&
1138
- path[key] != null &&
1141
+ valForKey != null &&
1139
1142
  pathtype === 'nested' &&
1140
1143
  this._doc[key] != null) {
1141
1144
  delete this._doc[key];
@@ -1313,7 +1316,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1313
1316
  let curPath = '';
1314
1317
  for (i = 0; i < parts.length - 1; ++i) {
1315
1318
  cur = cur[parts[i]];
1316
- curPath += (curPath.length > 0 ? '.' : '') + parts[i];
1319
+ curPath += (curPath.length !== 0 ? '.' : '') + parts[i];
1317
1320
  if (!cur) {
1318
1321
  this.$set(curPath, {});
1319
1322
  // Hack re: gh-5800. If nested field is not selected, it probably exists
@@ -1336,7 +1339,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
1336
1339
  if (parts.length <= 1) {
1337
1340
  pathToMark = path;
1338
1341
  } else {
1339
- for (i = 0; i < parts.length; ++i) {
1342
+ const len = parts.length;
1343
+ for (i = 0; i < len; ++i) {
1340
1344
  const subpath = parts.slice(0, i + 1).join('.');
1341
1345
  if (this.$get(subpath, null, { getters: false }) === null) {
1342
1346
  pathToMark = subpath;
@@ -1361,7 +1365,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1361
1365
  _markValidSubpaths(this, path);
1362
1366
  }
1363
1367
 
1364
- if (schema.$isSingleNested && val != null && merge) {
1368
+ if (val != null && merge && schema.$isSingleNested) {
1365
1369
  if (val instanceof Document) {
1366
1370
  val = val.toObject({ virtuals: false, transform: false });
1367
1371
  }
@@ -1431,9 +1435,10 @@ Document.prototype.$set = function $set(path, val, type, options) {
1431
1435
  val = schema.applySetters(val, this, false, priorVal);
1432
1436
  }
1433
1437
 
1434
- if (schema.$isMongooseDocumentArray &&
1435
- Array.isArray(val) &&
1436
- val.length > 0 &&
1438
+ if (Array.isArray(val) &&
1439
+ !Array.isArray(schema) &&
1440
+ schema.$isMongooseDocumentArray &&
1441
+ val.length !== 0 &&
1437
1442
  val[0] != null &&
1438
1443
  val[0].$__ != null &&
1439
1444
  val[0].$__.populated != null) {
@@ -1459,7 +1464,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1459
1464
  delete this.$__.populated[path];
1460
1465
  }
1461
1466
 
1462
- if (schema.$isSingleNested && val != null) {
1467
+ if (val != null && schema.$isSingleNested) {
1463
1468
  _checkImmutableSubpaths(val, schema, priorVal);
1464
1469
  }
1465
1470
 
@@ -1652,11 +1657,11 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
1652
1657
 
1653
1658
  // handle directly setting arrays (gh-1126)
1654
1659
  MongooseArray || (MongooseArray = require('./types/array'));
1655
- if (val && val.isMongooseArray) {
1660
+ if (val && utils.isMongooseArray(val)) {
1656
1661
  val._registerAtomic('$set', val);
1657
1662
 
1658
1663
  // Update embedded document parent references (gh-5189)
1659
- if (val.isMongooseDocumentArray) {
1664
+ if (utils.isMongooseDocumentArray(val)) {
1660
1665
  val.forEach(function(item) {
1661
1666
  item && item.__parentArray && (item.__parentArray = val);
1662
1667
  });
@@ -1670,10 +1675,10 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
1670
1675
  }
1671
1676
  });
1672
1677
  }
1673
- } else if (Array.isArray(val) && val.isMongooseArray && Array.isArray(priorVal) && priorVal.isMongooseArray) {
1678
+ } else if (Array.isArray(val) && Array.isArray(priorVal) && utils.isMongooseArray(val) && utils.isMongooseArray(priorVal)) {
1674
1679
  val[arrayAtomicsSymbol] = priorVal[arrayAtomicsSymbol];
1675
1680
  val[arrayAtomicsBackupSymbol] = priorVal[arrayAtomicsBackupSymbol];
1676
- if (val.isMongooseDocumentArray) {
1681
+ if (utils.isMongooseDocumentArray(val)) {
1677
1682
  val.forEach(doc => { doc.isNew = false; });
1678
1683
  }
1679
1684
  }
@@ -1702,7 +1707,7 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
1702
1707
  obj = obj[parts[i]];
1703
1708
  } else if (obj[parts[i]] && obj[parts[i]] instanceof Embedded) {
1704
1709
  obj = obj[parts[i]];
1705
- } else if (obj[parts[i]] && obj[parts[i]].$isSingleNested) {
1710
+ } else if (obj[parts[i]] && !Array.isArray(obj[parts[i]]) && obj[parts[i]].$isSingleNested) {
1706
1711
  obj = obj[parts[i]];
1707
1712
  } else if (obj[parts[i]] && Array.isArray(obj[parts[i]])) {
1708
1713
  obj = obj[parts[i]];
@@ -1963,7 +1968,7 @@ Document.prototype.$isEmpty = function(path) {
1963
1968
  transform: false
1964
1969
  };
1965
1970
 
1966
- if (arguments.length > 0) {
1971
+ if (arguments.length !== 0) {
1967
1972
  const v = this.$get(path);
1968
1973
  if (v == null) {
1969
1974
  return true;
@@ -2006,51 +2011,60 @@ function _isEmpty(v) {
2006
2011
 
2007
2012
  Document.prototype.modifiedPaths = function(options) {
2008
2013
  options = options || {};
2014
+
2009
2015
  const directModifiedPaths = Object.keys(this.$__.activePaths.states.modify);
2010
- const _this = this;
2011
- return directModifiedPaths.reduce(function(list, path) {
2012
- const parts = path.split('.');
2013
- list = list.concat(parts.reduce(function(chains, part, i) {
2014
- return chains.concat(parts.slice(0, i).concat(part).join('.'));
2015
- }, []).filter(function(chain) {
2016
- return (list.indexOf(chain) === -1);
2017
- }));
2016
+ const result = new Set();
2017
+
2018
+ let i = 0;
2019
+ let j = 0;
2020
+ const len = directModifiedPaths.length;
2021
+
2022
+ for (i = 0; i < len; ++i) {
2023
+ const path = directModifiedPaths[i];
2024
+ const parts = parentPaths(path);
2025
+ const pLen = parts.length;
2026
+
2027
+ for (j = 0; j < pLen; ++j) {
2028
+ result.add(parts[j]);
2029
+ }
2018
2030
 
2019
2031
  if (!options.includeChildren) {
2020
- return list;
2032
+ continue;
2021
2033
  }
2022
2034
 
2023
- let cur = _this.$get(path);
2024
- if (cur != null && typeof cur === 'object') {
2035
+ let ii = 0;
2036
+ let cur = this.$get(path);
2037
+ if (typeof cur === 'object' && cur !== null) {
2025
2038
  if (cur._doc) {
2026
2039
  cur = cur._doc;
2027
2040
  }
2041
+ const len = cur.length;
2028
2042
  if (Array.isArray(cur)) {
2029
- const len = cur.length;
2030
- for (let i = 0; i < len; ++i) {
2031
- if (list.indexOf(path + '.' + i) === -1) {
2032
- list.push(path + '.' + i);
2033
- if (cur[i] != null && cur[i].$__) {
2034
- const modified = cur[i].modifiedPaths();
2035
- for (const childPath of modified) {
2036
- list.push(path + '.' + i + '.' + childPath);
2043
+ for (ii = 0; ii < len; ++ii) {
2044
+ const subPath = path + '.' + ii;
2045
+ if (!result.has(subPath)) {
2046
+ result.add(subPath);
2047
+ if (cur[ii] != null && cur[ii].$__) {
2048
+ const modified = cur[ii].modifiedPaths();
2049
+ let iii = 0;
2050
+ const iiiLen = modified.length;
2051
+ for (iii = 0; iii < iiiLen; ++iii) {
2052
+ result.add(subPath + '.' + modified[iii]);
2037
2053
  }
2038
2054
  }
2039
2055
  }
2040
2056
  }
2041
2057
  } else {
2042
- Object.keys(cur).
2043
- filter(function(key) {
2044
- return list.indexOf(path + '.' + key) === -1;
2045
- }).
2046
- forEach(function(key) {
2047
- list.push(path + '.' + key);
2048
- });
2058
+ const keys = Object.keys(cur);
2059
+ let ii = 0;
2060
+ const len = keys.length;
2061
+ for (ii = 0; ii < len; ++ii) {
2062
+ result.add(path + '.' + keys[ii]);
2063
+ }
2049
2064
  }
2050
2065
  }
2051
-
2052
- return list;
2053
- }, []);
2066
+ }
2067
+ return Array.from(result);
2054
2068
  };
2055
2069
 
2056
2070
  Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
@@ -2448,7 +2462,12 @@ Document.prototype.$validate = Document.prototype.validate;
2448
2462
  */
2449
2463
 
2450
2464
  function _evaluateRequiredFunctions(doc) {
2451
- Object.keys(doc.$__.activePaths.states.require).forEach(path => {
2465
+ const requiredFields = Object.keys(doc.$__.activePaths.states.require);
2466
+ let i = 0;
2467
+ const len = requiredFields.length;
2468
+ for (i = 0; i < len; ++i) {
2469
+ const path = requiredFields[i];
2470
+
2452
2471
  const p = doc.$__schema.path(path);
2453
2472
 
2454
2473
  if (p != null && typeof p.originalRequiredValue === 'function') {
@@ -2459,7 +2478,7 @@ function _evaluateRequiredFunctions(doc) {
2459
2478
  doc.invalidate(path, err);
2460
2479
  }
2461
2480
  }
2462
- });
2481
+ }
2463
2482
  }
2464
2483
 
2465
2484
  /*!
@@ -2520,7 +2539,7 @@ function _getPathsToValidate(doc) {
2520
2539
  // To avoid potential performance issues, skip doc arrays whose children
2521
2540
  // are not required. `getPositionalPathType()` may be slow, so avoid
2522
2541
  // it unless we have a case of #6364
2523
- (_pathType.$isMongooseDocumentArray && !get(_pathType, 'schemaOptions.required'))) {
2542
+ (!Array.isArray(_pathType) && _pathType.$isMongooseDocumentArray && !get(_pathType, 'schemaOptions.required'))) {
2524
2543
  continue;
2525
2544
  }
2526
2545
 
@@ -3112,7 +3131,7 @@ Document.prototype.$__reset = function reset() {
3112
3131
  return _this.$__getValue(i);
3113
3132
  })
3114
3133
  .filter(function(val) {
3115
- return val && val instanceof Array && val.isMongooseDocumentArray && val.length;
3134
+ return val && val instanceof Array && utils.isMongooseDocumentArray(val) && val.length;
3116
3135
  })
3117
3136
  .forEach(function(array) {
3118
3137
  let i = array.length;
@@ -3135,7 +3154,7 @@ Document.prototype.$__reset = function reset() {
3135
3154
  return _this.$__getValue(i);
3136
3155
  }).
3137
3156
  filter(function(val) {
3138
- return val && val.$isSingleNested;
3157
+ return val && !Array.isArray(val) && val.$isSingleNested;
3139
3158
  }).
3140
3159
  forEach(function(doc) {
3141
3160
  doc.$__reset();
@@ -3315,7 +3334,7 @@ Document.prototype.$__getArrayPathsToValidate = function() {
3315
3334
  return this.$__getValue(i);
3316
3335
  }.bind(this))
3317
3336
  .filter(function(val) {
3318
- return val && val instanceof Array && val.isMongooseDocumentArray && val.length;
3337
+ return val && val instanceof Array && utils.isMongooseDocumentArray(val) && val.length;
3319
3338
  }).reduce(function(seed, array) {
3320
3339
  return seed.concat(array);
3321
3340
  }, [])
@@ -3357,12 +3376,12 @@ Document.prototype.$getAllSubdocs = function() {
3357
3376
  seed = Array.from(val.keys()).reduce(function(seed, path) {
3358
3377
  return docReducer(val.get(path), seed, null);
3359
3378
  }, seed);
3360
- } else if (val && val.$isSingleNested) {
3379
+ } else if (val && !Array.isArray(val) && val.$isSingleNested) {
3361
3380
  seed = Object.keys(val._doc).reduce(function(seed, path) {
3362
3381
  return docReducer(val._doc, seed, path);
3363
3382
  }, seed);
3364
3383
  seed.push(val);
3365
- } else if (val && val.isMongooseDocumentArray) {
3384
+ } else if (val && utils.isMongooseDocumentArray(val)) {
3366
3385
  val.forEach(function _docReduce(doc) {
3367
3386
  if (!doc || !doc._doc) {
3368
3387
  return;
@@ -3801,7 +3820,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
3801
3820
  if (!path.startsWith(options.path + '.')) {
3802
3821
  continue;
3803
3822
  }
3804
- assignPath = path.substr(options.path.length + 1);
3823
+ assignPath = path.substring(options.path.length + 1);
3805
3824
  }
3806
3825
  const parts = assignPath.split('.');
3807
3826
  v = clone(self.get(path), options);
@@ -4139,7 +4158,7 @@ Document.prototype.populate = function populate() {
4139
4158
  const args = [...arguments];
4140
4159
  let fn;
4141
4160
 
4142
- if (args.length > 0) {
4161
+ if (args.length !== 0) {
4143
4162
  if (typeof args[args.length - 1] === 'function') {
4144
4163
  fn = args.pop();
4145
4164
  }
@@ -181,6 +181,17 @@ MongooseError.OverwriteModelError = require('./overwriteModel');
181
181
 
182
182
  MongooseError.MissingSchemaError = require('./missingSchema');
183
183
 
184
+ /**
185
+ * Thrown when the MongoDB Node driver can't connect to a valid server
186
+ * to send an operation to.
187
+ *
188
+ * @api public
189
+ * @memberOf Error
190
+ * @static MongooseServerSelectionError
191
+ */
192
+
193
+ MongooseError.MongooseServerSelectionError = require('./serverSelection');
194
+
184
195
  /**
185
196
  * An instance of this error will be returned if you used an array projection
186
197
  * and then modified the array in an unsafe way.
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ /*!
4
+ * Module dependencies.
5
+ */
6
+
7
+ const MongooseError = require('./mongooseError');
8
+
9
+ /**
10
+ * SyncIndexes Error constructor.
11
+ *
12
+ * @param {String} message
13
+ * @param {String} errorsMap
14
+ * @inherits MongooseError
15
+ * @api private
16
+ */
17
+
18
+ class SyncIndexesError extends MongooseError {
19
+ constructor(message, errorsMap) {
20
+ super(message);
21
+ this.errors = errorsMap;
22
+ }
23
+ }
24
+
25
+ Object.defineProperty(SyncIndexesError.prototype, 'name', {
26
+ value: 'SyncIndexesError'
27
+ });
28
+
29
+
30
+ module.exports = SyncIndexesError;
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
-
4
- const cloneRegExp = require('regexp-clone');
5
3
  const Decimal = require('../types/decimal128');
6
4
  const ObjectId = require('../types/objectid');
7
5
  const specialProperties = require('./specialProperties');
@@ -34,7 +32,7 @@ function clone(obj, options, isArrayChild) {
34
32
  }
35
33
 
36
34
  if (Array.isArray(obj)) {
37
- return cloneArray(obj, options);
35
+ return cloneArray(utils.isMongooseArray(obj) ? obj.__array : obj, options);
38
36
  }
39
37
 
40
38
  if (isMongooseObject(obj)) {
@@ -54,12 +52,14 @@ function clone(obj, options, isArrayChild) {
54
52
  return obj.toObject(options);
55
53
  }
56
54
 
57
- if (obj.constructor) {
58
- switch (getFunctionName(obj.constructor)) {
55
+ const objConstructor = obj.constructor;
56
+
57
+ if (objConstructor) {
58
+ switch (getFunctionName(objConstructor)) {
59
59
  case 'Object':
60
60
  return cloneObject(obj, options, isArrayChild);
61
61
  case 'Date':
62
- return new obj.constructor(+obj);
62
+ return new objConstructor(+obj);
63
63
  case 'RegExp':
64
64
  return cloneRegExp(obj);
65
65
  default:
@@ -79,12 +79,12 @@ function clone(obj, options, isArrayChild) {
79
79
  return Decimal.fromString(obj.toString());
80
80
  }
81
81
 
82
- if (!obj.constructor && isObject(obj)) {
83
- // object created with Object.create(null)
82
+ // object created with Object.create(null)
83
+ if (!objConstructor && isObject(obj)) {
84
84
  return cloneObject(obj, options, isArrayChild);
85
85
  }
86
86
 
87
- if (obj[symbols.schemaTypeSymbol]) {
87
+ if (typeof obj === 'object' && obj[symbols.schemaTypeSymbol]) {
88
88
  return obj.clone();
89
89
  }
90
90
 
@@ -95,7 +95,7 @@ function clone(obj, options, isArrayChild) {
95
95
  return obj;
96
96
  }
97
97
 
98
- if (obj.valueOf != null) {
98
+ if (typeof obj.valueOf === 'function') {
99
99
  return obj.valueOf();
100
100
  }
101
101
 
@@ -112,25 +112,28 @@ function cloneObject(obj, options, isArrayChild) {
112
112
  const ret = {};
113
113
  let hasKeys;
114
114
 
115
- if (obj[trustedSymbol]) {
115
+ if (trustedSymbol in obj) {
116
116
  ret[trustedSymbol] = obj[trustedSymbol];
117
117
  }
118
118
 
119
- for (const k of Object.keys(obj)) {
120
- if (specialProperties.has(k)) {
119
+ let i = 0;
120
+ let key = '';
121
+ const keys = Object.keys(obj);
122
+ const len = keys.length;
123
+
124
+ for (i = 0; i < len; ++i) {
125
+ if (specialProperties.has(key = keys[i])) {
121
126
  continue;
122
127
  }
123
128
 
124
129
  // Don't pass `isArrayChild` down
125
- const val = clone(obj[k], options);
126
-
127
- if (!minimize || (typeof val !== 'undefined')) {
128
- if (minimize === false && typeof val === 'undefined') {
129
- delete ret[k];
130
- } else {
131
- hasKeys || (hasKeys = true);
132
- ret[k] = val;
133
- }
130
+ const val = clone(obj[key], options, false);
131
+
132
+ if (minimize === false && typeof val === 'undefined') {
133
+ delete ret[key];
134
+ } else if (minimize !== true || (typeof val !== 'undefined')) {
135
+ hasKeys || (hasKeys = true);
136
+ ret[key] = val;
134
137
  }
135
138
  }
136
139
 
@@ -138,11 +141,21 @@ function cloneObject(obj, options, isArrayChild) {
138
141
  }
139
142
 
140
143
  function cloneArray(arr, options) {
141
- const ret = [];
142
-
143
- for (const item of arr) {
144
- ret.push(clone(item, options, true));
144
+ let i = 0;
145
+ const len = arr.length;
146
+ const ret = new Array(len);
147
+ for (i = 0; i < len; ++i) {
148
+ ret[i] = clone(arr[i], options, true);
145
149
  }
146
150
 
147
151
  return ret;
148
- }
152
+ }
153
+
154
+ function cloneRegExp(regexp) {
155
+ const ret = new RegExp(regexp.source, regexp.flags);
156
+
157
+ if (ret.lastIndex !== regexp.lastIndex) {
158
+ ret.lastIndex = regexp.lastIndex;
159
+ }
160
+ return ret;
161
+ }