mongoose 6.8.0 → 6.8.2

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/lib/connection.js CHANGED
@@ -196,7 +196,7 @@ Connection.prototype.collections;
196
196
  *
197
197
  * #### Example:
198
198
  *
199
- * mongoose.createConnection('mongodb://localhost:27017/mydb').name; // "mydb"
199
+ * mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').name; // "mydb"
200
200
  *
201
201
  * @property name
202
202
  * @memberOf Connection
@@ -253,7 +253,7 @@ Connection.prototype.id;
253
253
  *
254
254
  * #### Example:
255
255
  *
256
- * const db = mongoose.createConnection('mongodb://localhost:27017/mydb');
256
+ * const db = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
257
257
  * db.plugin(() => console.log('Applied'));
258
258
  * db.plugins.length; // 1
259
259
  *
@@ -277,7 +277,7 @@ Object.defineProperty(Connection.prototype, 'plugins', {
277
277
  *
278
278
  * #### Example:
279
279
  *
280
- * mongoose.createConnection('mongodb://localhost:27017/mydb').host; // "localhost"
280
+ * mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').host; // "127.0.0.1"
281
281
  *
282
282
  * @property host
283
283
  * @memberOf Connection
@@ -297,7 +297,7 @@ Object.defineProperty(Connection.prototype, 'host', {
297
297
  *
298
298
  * #### Example:
299
299
  *
300
- * mongoose.createConnection('mongodb://localhost:27017/mydb').port; // 27017
300
+ * mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').port; // 27017
301
301
  *
302
302
  * @property port
303
303
  * @memberOf Connection
@@ -316,7 +316,7 @@ Object.defineProperty(Connection.prototype, 'port', {
316
316
  *
317
317
  * #### Example:
318
318
  *
319
- * mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').user; // "val"
319
+ * mongoose.createConnection('mongodb://val:psw@127.0.0.1:27017/mydb').user; // "val"
320
320
  *
321
321
  * @property user
322
322
  * @memberOf Connection
@@ -335,7 +335,7 @@ Object.defineProperty(Connection.prototype, 'user', {
335
335
  *
336
336
  * #### Example:
337
337
  *
338
- * mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').pass; // "psw"
338
+ * mongoose.createConnection('mongodb://val:psw@127.0.0.1:27017/mydb').pass; // "psw"
339
339
  *
340
340
  * @property pass
341
341
  * @memberOf Connection
@@ -539,7 +539,7 @@ Connection.prototype.dropCollection = _wrapConnHelper(function dropCollection(co
539
539
  *
540
540
  * #### Example:
541
541
  *
542
- * const conn = mongoose.createConnection('mongodb://localhost:27017/mydb');
542
+ * const conn = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
543
543
  * // Deletes the entire 'mydb' database
544
544
  * await conn.dropDatabase();
545
545
  *
@@ -1109,7 +1109,7 @@ Connection.prototype.collection = function(name, options) {
1109
1109
  *
1110
1110
  * #### Example:
1111
1111
  *
1112
- * const db = mongoose.createConnection('mongodb://localhost:27017/mydb');
1112
+ * const db = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb');
1113
1113
  * db.plugin(() => console.log('Applied'));
1114
1114
  * db.plugins.length; // 1
1115
1115
  *
@@ -1367,7 +1367,7 @@ Connection.prototype.watch = function(pipeline, options) {
1367
1367
  *
1368
1368
  * #### Example:
1369
1369
  *
1370
- * const conn = await mongoose.createConnection('mongodb://localhost:27017/test').
1370
+ * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/test').
1371
1371
  * asPromise();
1372
1372
  * conn.readyState; // 1, means Mongoose is connected
1373
1373
  *
@@ -1440,7 +1440,7 @@ Connection.prototype.optionsProvideAuthenticationData = function(options) {
1440
1440
  *
1441
1441
  * #### Example:
1442
1442
  *
1443
- * const conn = await mongoose.createConnection('mongodb://localhost:27017/test').
1443
+ * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/test').
1444
1444
  * asPromise();
1445
1445
  *
1446
1446
  * conn.getClient(); // MongoClient { ... }
@@ -1460,7 +1460,7 @@ Connection.prototype.getClient = function getClient() {
1460
1460
  *
1461
1461
  * #### Example:
1462
1462
  *
1463
- * const client = await mongodb.MongoClient.connect('mongodb://localhost:27017/test');
1463
+ * const client = await mongodb.MongoClient.connect('mongodb://127.0.0.1:27017/test');
1464
1464
  *
1465
1465
  * const conn = mongoose.createConnection().setClient(client);
1466
1466
  *
@@ -1538,7 +1538,7 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
1538
1538
  * #### Example:
1539
1539
  *
1540
1540
  * // Connect to `initialdb` first
1541
- * const conn = await mongoose.createConnection('mongodb://localhost:27017/initialdb').asPromise();
1541
+ * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise();
1542
1542
  *
1543
1543
  * // Creates an un-cached connection to `mydb`
1544
1544
  * const db = conn.useDb('mydb');
package/lib/document.js CHANGED
@@ -4655,7 +4655,7 @@ Document.prototype.getChanges = function() {
4655
4655
  * Returns a copy of this document with a deep clone of `_doc` and `$__`.
4656
4656
  *
4657
4657
  * @return {Document} a copy of this document
4658
- * @api private
4658
+ * @api public
4659
4659
  * @method $clone
4660
4660
  * @memberOf Document
4661
4661
  * @instance
@@ -106,6 +106,7 @@ updatePath: '${recursion.raw.path}'`);
106
106
  modifiedPaths(val, path + key, result, recursion);
107
107
  }
108
108
  }
109
+ recursion.trace.delete(update);
109
110
 
110
111
  return result;
111
112
  }
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const Mixed = require('../../schema/mixed');
4
+ const applyBuiltinPlugins = require('../schema/applyBuiltinPlugins');
4
5
  const defineKey = require('../document/compile').defineKey;
5
6
  const get = require('../get');
6
7
  const utils = require('../../utils');
@@ -40,6 +41,8 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
40
41
  model.base._applyPlugins(schema, {
41
42
  skipTopLevel: !applyPluginsToDiscriminators
42
43
  });
44
+ } else if (!mergeHooks) {
45
+ applyBuiltinPlugins(schema);
43
46
  }
44
47
 
45
48
  const key = model.schema.options.discriminatorKey;
@@ -43,6 +43,8 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re
43
43
 
44
44
  let i = 0;
45
45
  const len = rawIds.length;
46
+ const hasResultArrays = Object.values(resultOrder).find(o => Array.isArray(o));
47
+
46
48
  for (i = 0; i < len; ++i) {
47
49
  id = rawIds[i];
48
50
 
@@ -77,7 +79,8 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re
77
79
  if (doc) {
78
80
  if (sorting) {
79
81
  const _resultOrder = resultOrder[sid];
80
- if (Array.isArray(_resultOrder) && Array.isArray(doc) && _resultOrder.length === doc.length) {
82
+ if (hasResultArrays) {
83
+ // If result arrays, rely on the MongoDB server response for ordering
81
84
  newOrder.push(doc);
82
85
  } else {
83
86
  newOrder[_resultOrder] = doc;
@@ -253,6 +253,8 @@ function valueFilter(val, assignmentOpts, populateOptions, allIds) {
253
253
  const _allIds = Array.isArray(allIds) ? allIds[i] : allIds;
254
254
  if (!isPopulatedObject(subdoc) && (!populateOptions.retainNullValues || subdoc != null) && !userSpecifiedTransform) {
255
255
  continue;
256
+ } else if (!populateOptions.retainNullValues && subdoc == null) {
257
+ continue;
256
258
  } else if (userSpecifiedTransform) {
257
259
  subdoc = transform(isPopulatedObject(subdoc) ? subdoc : null, _allIds);
258
260
  }
@@ -84,6 +84,14 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
84
84
  const op = ops[i];
85
85
  val = ret[op];
86
86
  hasDollarKey = hasDollarKey || op.startsWith('$');
87
+ const toUnset = {};
88
+ if (val != null) {
89
+ for (const key of Object.keys(val)) {
90
+ if (val[key] === undefined) {
91
+ toUnset[key] = 1;
92
+ }
93
+ }
94
+ }
87
95
 
88
96
  if (val &&
89
97
  typeof val === 'object' &&
@@ -100,6 +108,10 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
100
108
 
101
109
  if (op.startsWith('$') && utils.isEmptyObject(val)) {
102
110
  delete ret[op];
111
+ if (op === '$set' && !utils.isEmptyObject(toUnset)) {
112
+ // Unset all undefined values
113
+ ret['$unset'] = toUnset;
114
+ }
103
115
  }
104
116
  }
105
117
 
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const builtinPlugins = require('../../plugins');
4
+
5
+ module.exports = function applyBuiltinPlugins(schema) {
6
+ for (const plugin of Object.values(builtinPlugins)) {
7
+ plugin(schema, { deduplicate: true });
8
+ }
9
+ schema.plugins = Object.values(builtinPlugins).
10
+ map(fn => ({ fn, opts: { deduplicate: true } })).
11
+ concat(schema.plugins);
12
+ };
@@ -37,14 +37,36 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
37
37
  if (filter == null) {
38
38
  throw new Error(`Got null array filter in ${arrayFilters}`);
39
39
  }
40
- for (const key of Object.keys(filter)) {
41
- if (key === '$and' || key === '$or') {
40
+ const keys = Object.keys(filter).filter(key => filter[key] != null);
41
+ if (keys.length === 0) {
42
+ continue;
43
+ }
44
+
45
+ const firstKey = keys[0];
46
+ if (firstKey === '$and' || firstKey === '$or') {
47
+ for (const key of keys) {
42
48
  _castArrayFilters(filter[key], schema, strictQuery, updatedPathsByFilter, query);
43
- continue;
44
- }
45
- if (filter[key] == null) {
46
- continue;
47
49
  }
50
+ continue;
51
+ }
52
+ const dot = firstKey.indexOf('.');
53
+ const filterWildcardPath = dot === -1 ? firstKey : firstKey.substring(0, dot);
54
+ if (updatedPathsByFilter[filterWildcardPath] == null) {
55
+ continue;
56
+ }
57
+ const baseFilterPath = cleanPositionalOperators(
58
+ updatedPathsByFilter[filterWildcardPath]
59
+ );
60
+
61
+ const baseSchematype = getPath(schema, baseFilterPath);
62
+ let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null;
63
+ if (filterBaseSchema != null &&
64
+ filterBaseSchema.discriminators != null &&
65
+ filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) {
66
+ filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema;
67
+ }
68
+
69
+ for (const key of keys) {
48
70
  if (updatedPathsByFilter[key] === null) {
49
71
  continue;
50
72
  }
@@ -52,21 +74,25 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
52
74
  continue;
53
75
  }
54
76
  const dot = key.indexOf('.');
55
- let filterPath = dot === -1 ?
56
- updatedPathsByFilter[key] + '.0' :
57
- updatedPathsByFilter[key.substring(0, dot)] + '.0' + key.substring(dot);
58
- if (filterPath == null) {
59
- throw new Error(`Filter path not found for ${key}`);
77
+
78
+ let filterPathRelativeToBase = dot === -1 ? null : key.substring(dot);
79
+ let schematype;
80
+ if (filterPathRelativeToBase == null || filterBaseSchema == null) {
81
+ schematype = baseSchematype;
82
+ } else {
83
+ // If there are multiple array filters in the path being updated, make sure
84
+ // to replace them so we can get the schema path.
85
+ filterPathRelativeToBase = cleanPositionalOperators(filterPathRelativeToBase);
86
+ schematype = getPath(filterBaseSchema, filterPathRelativeToBase);
60
87
  }
61
88
 
62
- // If there are multiple array filters in the path being updated, make sure
63
- // to replace them so we can get the schema path.
64
- filterPath = cleanPositionalOperators(filterPath);
65
- const schematype = getPath(schema, filterPath);
66
89
  if (schematype == null) {
67
90
  if (!strictQuery) {
68
91
  return;
69
92
  }
93
+ const filterPath = filterPathRelativeToBase == null ?
94
+ baseFilterPath + '.0' :
95
+ baseFilterPath + '.0' + filterPathRelativeToBase;
70
96
  // For now, treat `strictQuery = true` and `strictQuery = 'throw'` as
71
97
  // equivalent for casting array filters. `strictQuery = true` doesn't
72
98
  // quite work in this context because we never want to silently strip out
package/lib/index.js CHANGED
@@ -19,21 +19,17 @@ const Types = require('./types');
19
19
  const Query = require('./query');
20
20
  const Model = require('./model');
21
21
  const applyPlugins = require('./helpers/schema/applyPlugins');
22
+ const builtinPlugins = require('./plugins');
22
23
  const driver = require('./driver');
23
24
  const promiseOrCallback = require('./helpers/promiseOrCallback');
24
25
  const legacyPluralize = require('./helpers/pluralize');
25
26
  const utils = require('./utils');
26
27
  const pkg = require('../package.json');
27
28
  const cast = require('./cast');
28
- const removeSubdocs = require('./plugins/removeSubdocs');
29
- const saveSubdocs = require('./plugins/saveSubdocs');
30
- const trackTransaction = require('./plugins/trackTransaction');
31
- const validateBeforeSave = require('./plugins/validateBeforeSave');
32
29
 
33
30
  const Aggregate = require('./aggregate');
34
31
  const PromiseProvider = require('./promise_provider');
35
32
  const printStrictQueryWarning = require('./helpers/printStrictQueryWarning');
36
- const shardingPlugin = require('./plugins/sharding');
37
33
  const trusted = require('./helpers/query/trusted').trusted;
38
34
  const sanitizeFilter = require('./helpers/query/sanitizeFilter');
39
35
  const isBsonType = require('./helpers/isBsonType');
@@ -108,13 +104,7 @@ function Mongoose(options) {
108
104
  configurable: false,
109
105
  enumerable: true,
110
106
  writable: false,
111
- value: [
112
- [saveSubdocs, { deduplicate: true }],
113
- [validateBeforeSave, { deduplicate: true }],
114
- [shardingPlugin, { deduplicate: true }],
115
- [removeSubdocs, { deduplicate: true }],
116
- [trackTransaction, { deduplicate: true }]
117
- ]
107
+ value: Object.values(builtinPlugins).map(plugin => ([plugin, { deduplicate: true }]))
118
108
  });
119
109
  }
120
110
 
@@ -198,26 +188,28 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
198
188
  * mongoose.set({ debug: true, autoIndex: false }); // set multiple options at once
199
189
  *
200
190
  * Currently supported options are:
201
- * - 'applyPluginsToChildSchemas': `true` by default. Set to false to skip applying global plugins to child schemas
202
- * - 'applyPluginsToDiscriminators': `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
203
- * - 'autoCreate': Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model-createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
204
- * - 'autoIndex': `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
205
- * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
206
- * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
207
- * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
208
- * - 'cloneSchemas': `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
209
- * - 'timestamps.createdAt.immutable': `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt`
210
- * - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
211
- * - 'objectIdGetter': `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
212
- * - 'overwriteModels': Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
213
- * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
214
- * - 'runValidators': `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
215
- * - 'sanitizeFilter': `false` by default. Set to true to enable the [sanitization of the query filters](/docs/api/mongoose.html#mongoose_Mongoose-sanitizeFilter) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
216
- * - 'selectPopulatedPaths': `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
217
- * - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
218
- * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas. The default value will be switched back to `false` in Mongoose 7, use `mongoose.set('strictQuery', false);` if you want to prepare for the change.
219
- * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api/document.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
220
- * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api/document.html#document_Document-toObject)
191
+ * - `allowDiskUse`: Set to `true` to set `allowDiskUse` to true to all aggregation operations by default.
192
+ * - `applyPluginsToChildSchemas`: `true` by default. Set to false to skip applying global plugins to child schemas
193
+ * - `applyPluginsToDiscriminators`: `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
194
+ * - `autoCreate`: Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model-createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
195
+ * - `autoIndex`: `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
196
+ * - `bufferCommands`: enable/disable mongoose's buffering mechanism for all connections and models
197
+ * - `bufferTimeoutMS`: If bufferCommands is on, this option sets the maximum amount of time Mongoose buffering will wait before throwing an error. If not specified, Mongoose will use 10000 (10 seconds).
198
+ * - `cloneSchemas`: `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
199
+ * - `debug`: If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
200
+ * - `id`: If `true`, adds a `id` virtual to all schemas unless overwritten on a per-schema basis.
201
+ * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt`
202
+ * - `maxTimeMS`: If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
203
+ * - `objectIdGetter`: `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
204
+ * - `overwriteModels`: Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
205
+ * - `returnOriginal`: If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
206
+ * - `runValidators`: `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
207
+ * - `sanitizeFilter`: `false` by default. Set to true to enable the [sanitization of the query filters](/docs/api/mongoose.html#mongoose_Mongoose-sanitizeFilter) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
208
+ * - `selectPopulatedPaths`: `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
209
+ * - `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
210
+ * - `strictQuery`: same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas. The default value will be switched back to `false` in Mongoose 7, use `mongoose.set('strictQuery', false);` if you want to prepare for the change.
211
+ * - `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api/document.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
212
+ * - `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api/document.html#document_Document-toObject)
221
213
  *
222
214
  * @param {String|Object} key The name of the option or a object of multiple key-value pairs
223
215
  * @param {String|Function|Boolean} value The value of the option, unused if "key" is a object
@@ -309,22 +301,22 @@ Mongoose.prototype.get = Mongoose.prototype.set;
309
301
  * #### Example:
310
302
  *
311
303
  * // with mongodb:// URI
312
- * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database');
304
+ * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database');
313
305
  *
314
306
  * // and options
315
307
  * const opts = { db: { native_parser: true }}
316
- * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts);
308
+ * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database', opts);
317
309
  *
318
310
  * // replica sets
319
- * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database');
311
+ * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database');
320
312
  *
321
313
  * // and options
322
314
  * const opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
323
- * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
315
+ * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database', opts);
324
316
  *
325
317
  * // initialize now, connect later
326
318
  * db = mongoose.createConnection();
327
- * db.openUri('localhost', 'database', port, [opts]);
319
+ * db.openUri('127.0.0.1', 'database', port, [opts]);
328
320
  *
329
321
  * @param {String} uri mongodb URI to connect to
330
322
  * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html), except for 4 mongoose-specific options explained below.
@@ -367,10 +359,10 @@ Mongoose.prototype.createConnection = function(uri, options, callback) {
367
359
  *
368
360
  * #### Example:
369
361
  *
370
- * mongoose.connect('mongodb://user:pass@localhost:port/database');
362
+ * mongoose.connect('mongodb://user:pass@127.0.0.1:port/database');
371
363
  *
372
364
  * // replica sets
373
- * const uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase';
365
+ * const uri = 'mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/mydatabase';
374
366
  * mongoose.connect(uri);
375
367
  *
376
368
  * // with options
@@ -786,7 +778,7 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
786
778
  * mongoose.connections.length; // 1, just the default connection
787
779
  * mongoose.connections[0] === mongoose.connection; // true
788
780
  *
789
- * mongoose.createConnection('mongodb://localhost:27017/test');
781
+ * mongoose.createConnection('mongodb://127.0.0.1:27017/test');
790
782
  * mongoose.connections.length; // 2
791
783
  *
792
784
  * @memberOf Mongoose
package/lib/model.js CHANGED
@@ -36,6 +36,7 @@ const assignVals = require('./helpers/populate/assignVals');
36
36
  const castBulkWrite = require('./helpers/model/castBulkWrite');
37
37
  const createPopulateQueryFilter = require('./helpers/populate/createPopulateQueryFilter');
38
38
  const getDefaultBulkwriteResult = require('./helpers/getDefaultBulkwriteResult');
39
+ const getSchemaDiscriminatorByValue = require('./helpers/discriminator/getSchemaDiscriminatorByValue');
39
40
  const discriminator = require('./helpers/model/discriminator');
40
41
  const firstKey = require('./helpers/firstKey');
41
42
  const each = require('./helpers/each');
@@ -1570,14 +1571,14 @@ Model.diffIndexes = function diffIndexes(options, callback) {
1570
1571
  const schemaIndexes = getRelatedSchemaIndexes(model, schema.indexes());
1571
1572
 
1572
1573
  const toDrop = getIndexesToDrop(schema, schemaIndexes, dbIndexes);
1573
- const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes);
1574
+ const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop);
1574
1575
 
1575
1576
  cb(null, { toDrop, toCreate });
1576
1577
  });
1577
1578
  });
1578
1579
  };
1579
1580
 
1580
- function getIndexesToCreate(schema, schemaIndexes, dbIndexes) {
1581
+ function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop) {
1581
1582
  const toCreate = [];
1582
1583
 
1583
1584
  for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
@@ -1589,7 +1590,10 @@ function getIndexesToCreate(schema, schemaIndexes, dbIndexes) {
1589
1590
  if (isDefaultIdIndex(index)) {
1590
1591
  continue;
1591
1592
  }
1592
- if (isIndexEqual(schemaIndexKeysObject, options, index)) {
1593
+ if (
1594
+ isIndexEqual(schemaIndexKeysObject, options, index) &&
1595
+ !toDrop.includes(index.name)
1596
+ ) {
1593
1597
  found = true;
1594
1598
  break;
1595
1599
  }
@@ -1887,6 +1891,12 @@ function _ensureIndexes(model, options, callback) {
1887
1891
  indexOptions.background = options.background;
1888
1892
  }
1889
1893
 
1894
+ if ('toCreate' in options) {
1895
+ if (options.toCreate.length === 0) {
1896
+ return done();
1897
+ }
1898
+ }
1899
+
1890
1900
  model.collection.createIndex(indexFields, indexOptions, utils.tick(function(err, name) {
1891
1901
  indexSingleDone(err, indexFields, indexOptions, name);
1892
1902
  if (err) {
@@ -4465,7 +4475,11 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
4465
4475
  }
4466
4476
 
4467
4477
  return this.db.base._promiseOrCallback(callback, cb => {
4468
- const schema = this.schema;
4478
+ let schema = this.schema;
4479
+ const discriminatorKey = schema.options.discriminatorKey;
4480
+ if (schema.discriminators != null && obj != null && obj[discriminatorKey] != null) {
4481
+ schema = getSchemaDiscriminatorByValue(schema, obj[discriminatorKey]) || schema;
4482
+ }
4469
4483
  let paths = Object.keys(schema.paths);
4470
4484
 
4471
4485
  if (pathsToValidate != null) {
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ exports.removeSubdocs = require('./removeSubdocs');
4
+ exports.saveSubdocs = require('./saveSubdocs');
5
+ exports.sharding = require('./sharding');
6
+ exports.trackTransaction = require('./trackTransaction');
7
+ exports.validateBeforeSave = require('./validateBeforeSave');
package/lib/query.js CHANGED
@@ -370,17 +370,33 @@ Query.prototype.clone = function clone() {
370
370
  *
371
371
  * #### Example:
372
372
  *
373
- * query.slice('comments', 5);
374
- * query.slice('comments', -5);
375
- * query.slice('comments', [10, 5]);
376
- * query.where('comments').slice(5);
377
- * query.where('comments').slice([-10, 5]);
373
+ * query.slice('comments', 5); // Returns the first 5 comments
374
+ * query.slice('comments', -5); // Returns the last 5 comments
375
+ * query.slice('comments', [10, 5]); // Returns the first 5 comments after the 10-th
376
+ * query.where('comments').slice(5); // Returns the first 5 comments
377
+ * query.where('comments').slice([-10, 5]); // Returns the first 5 comments after the 10-th to last
378
+ *
379
+ * **Note:** If the absolute value of the number of elements to be sliced is greater than the number of elements in the array, all array elements will be returned.
380
+ *
381
+ * // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
382
+ * query.slice('arr', 20); // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
383
+ * query.slice('arr', -20); // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
384
+ *
385
+ * **Note:** If the number of elements to skip is positive and greater than the number of elements in the array, an empty array will be returned.
386
+ *
387
+ * // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
388
+ * query.slice('arr', [20, 5]); // Returns []
389
+ *
390
+ * **Note:** If the number of elements to skip is negative and its absolute value is greater than the number of elements in the array, the starting position is the start of the array.
391
+ *
392
+ * // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
393
+ * query.slice('arr', [-20, 5]); // Returns [1, 2, 3, 4, 5]
378
394
  *
379
395
  * @method slice
380
396
  * @memberOf Query
381
397
  * @instance
382
398
  * @param {String} [path]
383
- * @param {Number} val number/range of elements to slice
399
+ * @param {Number|Array} val number of elements to slice or array with number of elements to skip and number of elements to slice
384
400
  * @return {Query} this
385
401
  * @see mongodb https://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements
386
402
  * @see $slice https://docs.mongodb.org/manual/reference/projection/slice/#prj._S_slice
package/lib/schema.js CHANGED
@@ -1250,6 +1250,9 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1250
1250
  if (options.hasOwnProperty('strict')) {
1251
1251
  childSchemaOptions.strict = options.strict;
1252
1252
  }
1253
+ if (options.hasOwnProperty('strictQuery')) {
1254
+ childSchemaOptions.strictQuery = options.strictQuery;
1255
+ }
1253
1256
 
1254
1257
  if (this._userProvidedOptions.hasOwnProperty('_id')) {
1255
1258
  childSchemaOptions._id = this._userProvidedOptions._id;
package/lib/types/map.js CHANGED
@@ -180,7 +180,7 @@ class MongooseMap extends Map {
180
180
  }
181
181
 
182
182
  this.set(key, undefined);
183
- super.delete(key);
183
+ return super.delete(key);
184
184
  }
185
185
 
186
186
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "6.8.0",
4
+ "version": "6.8.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -36,7 +36,7 @@
36
36
  "acquit-ignore": "0.2.0",
37
37
  "acquit-require": "0.1.1",
38
38
  "assert-browserify": "2.0.0",
39
- "axios": "1.2.0",
39
+ "axios": "1.1.3",
40
40
  "babel-loader": "8.2.5",
41
41
  "benchmark": "2.1.4",
42
42
  "bluebird": "3.7.2",
@@ -61,9 +61,8 @@
61
61
  "q": "1.5.1",
62
62
  "sinon": "15.0.0",
63
63
  "stream-browserify": "3.0.0",
64
- "ts-benchmark": "^1.1.10",
65
64
  "tsd": "0.25.0",
66
- "typescript": "4.8.4",
65
+ "typescript": "4.9.4",
67
66
  "uuid": "9.0.0",
68
67
  "webpack": "5.75.0"
69
68
  },
@@ -100,8 +99,7 @@
100
99
  "test-tsd": "node ./test/types/check-types-filename && tsd",
101
100
  "tdd": "mocha ./test/*.test.js --inspect --watch --recursive --watch-files ./**/*.{js,ts}",
102
101
  "test-coverage": "nyc --reporter=html --reporter=text npm test",
103
- "ts-benchmark": "ts-benchmark -p ./benchmarks/typescript/simple -f 17/100000 18 29 32",
104
- "ts-benchmark-watch": "ts-benchmark -p ./benchmarks/typescript/simple -w ./types -i -s -f 17/100000 18 29 32 -b master"
102
+ "ts-benchmark": "cd ./benchmarks/typescript/simple && npm install && npm run benchmark | node ../../../scripts/tsc-diagnostics-check"
105
103
  },
106
104
  "main": "./index.js",
107
105
  "types": "./types/index.d.ts",
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+
5
+ const stdin = fs.readFileSync(0).toString('utf8');
6
+ const maxInstantiations = isNaN(process.argv[2]) ? 100000 : parseInt(process.argv[2], 10);
7
+
8
+ console.log(stdin);
9
+
10
+ const numInstantiations = parseInt(stdin.match(/Instantiations:\s+(\d+)/)[1], 10);
11
+ if (numInstantiations > maxInstantiations) {
12
+ throw new Error(`Instantiations ${numInstantiations} > max ${maxInstantiations}`);
13
+ }
14
+
15
+ process.exit(0);