mongoose 6.2.11 → 6.3.0

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/aggregate.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  const AggregationCursor = require('./cursor/AggregationCursor');
8
8
  const Query = require('./query');
9
- const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
9
+ const { applyGlobalMaxTimeMS, applyGlobalDiskUse } = require('./helpers/query/applyGlobalOption');
10
10
  const getConstructorName = require('./helpers/getConstructorName');
11
11
  const prepareDiscriminatorPipeline = require('./helpers/aggregate/prepareDiscriminatorPipeline');
12
12
  const promiseOrCallback = require('./helpers/promiseOrCallback');
@@ -15,6 +15,8 @@ const utils = require('./utils');
15
15
  const read = Query.prototype.read;
16
16
  const readConcern = Query.prototype.readConcern;
17
17
 
18
+ const validRedactStringValues = new Set(['$$DESCEND', '$$PRUNE', '$$KEEP']);
19
+
18
20
  /**
19
21
  * Aggregate constructor used for building aggregation pipelines. Do not
20
22
  * instantiate this class directly, use [Model.aggregate()](/docs/api.html#model_Model.aggregate) instead.
@@ -672,8 +674,6 @@ Aggregate.prototype.readConcern = function(level) {
672
674
  * @api public
673
675
  */
674
676
 
675
- const validRedactStringValues = new Set(['$$DESCEND', '$$PRUNE', '$$KEEP']);
676
-
677
677
  Aggregate.prototype.redact = function(expression, thenExpr, elseExpr) {
678
678
  if (arguments.length === 3) {
679
679
  if ((typeof thenExpr === 'string' && !validRedactStringValues.has(thenExpr)) ||
@@ -973,6 +973,7 @@ Aggregate.prototype.exec = function(callback) {
973
973
  const collection = this._model.collection;
974
974
 
975
975
  applyGlobalMaxTimeMS(this.options, model);
976
+ applyGlobalDiskUse(this.options, model);
976
977
 
977
978
  if (this.options && this.options.cursor) {
978
979
  return new AggregationCursor(this);
@@ -16,6 +16,7 @@ class ChangeStream extends EventEmitter {
16
16
 
17
17
  this.driverChangeStream = null;
18
18
  this.closed = false;
19
+ this.bindedEvents = false;
19
20
  this.pipeline = pipeline;
20
21
  this.options = options;
21
22
 
@@ -27,21 +28,60 @@ class ChangeStream extends EventEmitter {
27
28
  }
28
29
 
29
30
  this.driverChangeStream = driverChangeStream;
30
- this._bindEvents();
31
31
  this.emit('ready');
32
32
  });
33
33
  }
34
34
 
35
35
  _bindEvents() {
36
+ if (this.bindedEvents) {
37
+ return;
38
+ }
39
+
40
+ this.bindedEvents = true;
41
+
42
+ if (this.driverChangeStream == null) {
43
+ this.once('ready', () => {
44
+ this.driverChangeStream.on('close', () => {
45
+ this.closed = true;
46
+ });
47
+
48
+ ['close', 'change', 'end', 'error'].forEach(ev => {
49
+ this.driverChangeStream.on(ev, data => this.emit(ev, data));
50
+ });
51
+ });
52
+
53
+ return;
54
+ }
55
+
36
56
  this.driverChangeStream.on('close', () => {
37
57
  this.closed = true;
38
58
  });
39
59
 
40
60
  ['close', 'change', 'end', 'error'].forEach(ev => {
41
- this.driverChangeStream.on(ev, data => this.emit(ev, data));
61
+ this.driverChangeStream.on(ev, data => {
62
+ this.emit(ev, data);
63
+ });
42
64
  });
43
65
  }
44
66
 
67
+ hasNext(cb) {
68
+ return this.driverChangeStream.hasNext(cb);
69
+ }
70
+
71
+ next(cb) {
72
+ return this.driverChangeStream.next(cb);
73
+ }
74
+
75
+ on(event, handler) {
76
+ this._bindEvents();
77
+ return super.on(event, handler);
78
+ }
79
+
80
+ once(event, handler) {
81
+ this._bindEvents();
82
+ return super.once(event, handler);
83
+ }
84
+
45
85
  _queue(cb) {
46
86
  this.once('ready', () => cb());
47
87
  }
@@ -225,6 +225,8 @@ QueryCursor.prototype.next = function(callback) {
225
225
  * @param {Function} fn
226
226
  * @param {Object} [options]
227
227
  * @param {Number} [options.parallel] the number of promises to execute in parallel. Defaults to 1.
228
+ * @param {Number} [options.batchSize] if set, will call `fn()` with arrays of documents with length at most `batchSize`
229
+ * @param {Boolean} [options.continueOnError=false] if true, `eachAsync()` iterates through all docs even if `fn` throws an error. If false, `eachAsync()` throws an error immediately if the given function `fn()` throws an error.
228
230
  * @param {Function} [callback] executed when all docs have been processed
229
231
  * @return {Promise}
230
232
  * @api public
@@ -0,0 +1,41 @@
1
+ /*!
2
+ * Module dependencies.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const MongooseError = require('./');
8
+
9
+
10
+ /**
11
+ * If `eachAsync()` is called with `continueOnError: true`, there can be
12
+ * multiple errors. This error class contains an `errors` property, which
13
+ * contains an array of all errors that occurred in `eachAsync()`.
14
+ *
15
+ * @api private
16
+ */
17
+
18
+ class EachAsyncMultiError extends MongooseError {
19
+ /**
20
+ * @param {String} connectionString
21
+ */
22
+ constructor(errors) {
23
+ let preview = errors.map(e => e.message).join(', ');
24
+ if (preview.length > 50) {
25
+ preview = preview.slice(0, 50) + '...';
26
+ }
27
+ super(`eachAsync() finished with ${errors.length} errors: ${preview}`);
28
+
29
+ this.errors = errors;
30
+ }
31
+ }
32
+
33
+ Object.defineProperty(EachAsyncMultiError.prototype, 'name', {
34
+ value: 'EachAsyncMultiError'
35
+ });
36
+
37
+ /*!
38
+ * exports
39
+ */
40
+
41
+ module.exports = EachAsyncMultiError;
@@ -4,6 +4,7 @@
4
4
  * Module dependencies.
5
5
  */
6
6
 
7
+ const EachAsyncMultiError = require('../../error/eachAsyncMultiError');
7
8
  const immediate = require('../immediate');
8
9
  const promiseOrCallback = require('../promiseOrCallback');
9
10
 
@@ -24,10 +25,11 @@ const promiseOrCallback = require('../promiseOrCallback');
24
25
  module.exports = function eachAsync(next, fn, options, callback) {
25
26
  const parallel = options.parallel || 1;
26
27
  const batchSize = options.batchSize;
28
+ const continueOnError = options.continueOnError;
29
+ const aggregatedErrors = [];
27
30
  const enqueue = asyncQueue();
28
31
 
29
32
  return promiseOrCallback(callback, cb => {
30
-
31
33
  if (batchSize != null) {
32
34
  if (typeof batchSize !== 'number') {
33
35
  throw new TypeError('batchSize must be a number');
@@ -62,14 +64,22 @@ module.exports = function eachAsync(next, fn, options, callback) {
62
64
  return done();
63
65
  }
64
66
  if (err != null) {
65
- error = err;
66
- finalCallback(err);
67
- return done();
67
+ if (continueOnError) {
68
+ aggregatedErrors.push(err);
69
+ } else {
70
+ error = err;
71
+ finalCallback(err);
72
+ return done();
73
+ }
68
74
  }
69
75
  if (doc == null) {
70
76
  drained = true;
71
77
  if (handleResultsInProgress <= 0) {
72
- finalCallback(null);
78
+ const finalErr = continueOnError ?
79
+ createEachAsyncMultiError(aggregatedErrors) :
80
+ error;
81
+
82
+ finalCallback(finalErr);
73
83
  } else if (batchSize && documentsBatch.length) {
74
84
  handleNextResult(documentsBatch, currentDocumentIndex++, handleNextResultCallBack);
75
85
  }
@@ -102,11 +112,18 @@ module.exports = function eachAsync(next, fn, options, callback) {
102
112
  --handleResultsInProgress;
103
113
  }
104
114
  if (err != null) {
105
- error = err;
106
- return finalCallback(err);
115
+ if (continueOnError) {
116
+ aggregatedErrors.push(err);
117
+ } else {
118
+ error = err;
119
+ return finalCallback(err);
120
+ }
107
121
  }
108
122
  if (drained && handleResultsInProgress <= 0) {
109
- return finalCallback(null);
123
+ const finalErr = continueOnError ?
124
+ createEachAsyncMultiError(aggregatedErrors) :
125
+ error;
126
+ return finalCallback(finalErr);
110
127
  }
111
128
 
112
129
  immediate(() => enqueue(fetch));
@@ -118,11 +135,18 @@ module.exports = function eachAsync(next, fn, options, callback) {
118
135
  }
119
136
 
120
137
  function handleNextResult(doc, i, callback) {
121
- const promise = fn(doc, i);
122
- if (promise && typeof promise.then === 'function') {
123
- promise.then(
138
+ let maybePromise;
139
+ try {
140
+ maybePromise = fn(doc, i);
141
+ } catch (err) {
142
+ return callback(err);
143
+ }
144
+ if (maybePromise && typeof maybePromise.then === 'function') {
145
+ maybePromise.then(
124
146
  function() { callback(null); },
125
- function(error) { callback(error || new Error('`eachAsync()` promise rejected without error')); });
147
+ function(error) {
148
+ callback(error || new Error('`eachAsync()` promise rejected without error'));
149
+ });
126
150
  } else {
127
151
  callback(null);
128
152
  }
@@ -158,3 +182,11 @@ function asyncQueue() {
158
182
  }
159
183
  }
160
184
  }
185
+
186
+ function createEachAsyncMultiError(aggregatedErrors) {
187
+ if (aggregatedErrors.length === 0) {
188
+ return null;
189
+ }
190
+
191
+ return new EachAsyncMultiError(aggregatedErrors);
192
+ }
@@ -17,7 +17,6 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
17
17
  */
18
18
 
19
19
  module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
20
-
21
20
  if (!(schema && schema.instanceOfSchema)) {
22
21
  throw new Error('You must pass a valid discriminator Schema');
23
22
  }
@@ -109,7 +108,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
109
108
 
110
109
  utils.merge(schema, baseSchema, {
111
110
  isDiscriminatorSchemaMerge: true,
112
- omit: { discriminators: true, base: true },
111
+ omit: { discriminators: true, base: true, _applyDiscriminators: true },
113
112
  omitNested: conflictingPaths.reduce((cur, path) => {
114
113
  cur['tree.' + path] = true;
115
114
  return cur;
@@ -141,7 +140,6 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
141
140
  obj[key][schema.options.typeKey] = existingPath ? existingPath.options[schema.options.typeKey] : String;
142
141
  schema.add(obj);
143
142
 
144
-
145
143
  schema.discriminatorMapping = { key: key, value: value, isRoot: false };
146
144
 
147
145
  if (baseSchema.options.collection) {
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ const utils = require('../../utils');
4
+
5
+ function applyGlobalMaxTimeMS(options, model) {
6
+ applyGlobalOption(options, model, 'maxTimeMS');
7
+ }
8
+
9
+ function applyGlobalDiskUse(options, model) {
10
+ applyGlobalOption(options, model, 'allowDiskUse');
11
+ }
12
+
13
+ module.exports = {
14
+ applyGlobalMaxTimeMS,
15
+ applyGlobalDiskUse
16
+ };
17
+
18
+
19
+ function applyGlobalOption(options, model, optionName) {
20
+ if (utils.hasUserDefinedProperty(options, optionName)) {
21
+ return;
22
+ }
23
+
24
+ if (utils.hasUserDefinedProperty(model.db.options, optionName)) {
25
+ options[optionName] = model.db.options[optionName];
26
+ } else if (utils.hasUserDefinedProperty(model.base.options, optionName)) {
27
+ options[optionName] = model.base.options[optionName];
28
+ }
29
+ }
package/lib/index.js CHANGED
@@ -179,7 +179,9 @@ Mongoose.prototype.driver = driver;
179
179
  Mongoose.prototype.set = function(key, value) {
180
180
  const _mongoose = this instanceof Mongoose ? this : mongoose;
181
181
 
182
- if (VALID_OPTIONS.indexOf(key) === -1) throw new Error(`\`${key}\` is an invalid option.`);
182
+ if (VALID_OPTIONS.indexOf(key) === -1) {
183
+ throw new Error(`\`${key}\` is an invalid option.`);
184
+ }
183
185
 
184
186
  if (arguments.length === 1) {
185
187
  return _mongoose.options[key];
@@ -467,6 +469,7 @@ Mongoose.prototype.pluralize = function(fn) {
467
469
  */
468
470
 
469
471
  Mongoose.prototype.model = function(name, schema, collection, options) {
472
+
470
473
  const _mongoose = this instanceof Mongoose ? this : mongoose;
471
474
 
472
475
  if (typeof schema === 'string') {
@@ -519,7 +522,6 @@ Mongoose.prototype.model = function(name, schema, collection, options) {
519
522
  }
520
523
 
521
524
  const model = _mongoose._model(name, schema, collection, options);
522
-
523
525
  _mongoose.connection.models[name] = model;
524
526
  _mongoose.models[name] = model;
525
527
 
@@ -561,12 +563,17 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
561
563
 
562
564
  const connection = options.connection || _mongoose.connection;
563
565
  model = _mongoose.Model.compile(model || name, schema, collection, connection, _mongoose);
564
-
565
566
  // Errors handled internally, so safe to ignore error
566
567
  model.init(function $modelInitNoop() {});
567
568
 
568
569
  connection.emit('model', model);
569
570
 
571
+ if (schema._applyDiscriminators != null) {
572
+ for (const disc of Object.keys(schema._applyDiscriminators)) {
573
+ model.discriminator(disc, schema._applyDiscriminators[disc]);
574
+ }
575
+ }
576
+
570
577
  return model;
571
578
  };
572
579
 
package/lib/model.js CHANGED
@@ -4212,7 +4212,6 @@ Model.aggregate = function aggregate(pipeline, options, callback) {
4212
4212
 
4213
4213
  const aggregate = new Aggregate(pipeline || []);
4214
4214
  aggregate.model(this);
4215
-
4216
4215
  if (options != null) {
4217
4216
  aggregate.option(options);
4218
4217
  }
@@ -4809,7 +4808,6 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
4809
4808
  o[schema.options.versionKey] = Number;
4810
4809
  schema.add(o);
4811
4810
  }
4812
-
4813
4811
  let model;
4814
4812
  if (typeof name === 'function' && name.prototype instanceof Model) {
4815
4813
  model = name;
@@ -4853,6 +4851,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
4853
4851
  model.model = function model(name) {
4854
4852
  return this.db.model(name);
4855
4853
  };
4854
+
4856
4855
  model.db = connection;
4857
4856
  model.prototype.db = connection;
4858
4857
  model.prototype[modelDbSymbol] = connection;
package/lib/query.js CHANGED
@@ -12,7 +12,7 @@ const ObjectParameterError = require('./error/objectParameter');
12
12
  const QueryCursor = require('./cursor/QueryCursor');
13
13
  const ReadPreference = require('./driver').get().ReadPreference;
14
14
  const ValidationError = require('./error/validation');
15
- const applyGlobalMaxTimeMS = require('./helpers/query/applyGlobalMaxTimeMS');
15
+ const { applyGlobalMaxTimeMS, applyGlobalDiskUse } = require('./helpers/query/applyGlobalOption');
16
16
  const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
17
17
  const cast = require('./cast');
18
18
  const castArrayFilters = require('./helpers/update/castArrayFilters');
@@ -2192,6 +2192,7 @@ function _castArrayFilters(query) {
2192
2192
  * @api private
2193
2193
  */
2194
2194
  Query.prototype._find = wrapThunk(function(callback) {
2195
+
2195
2196
  this._castConditions();
2196
2197
 
2197
2198
  if (this.error() != null) {
@@ -2210,6 +2211,7 @@ Query.prototype._find = wrapThunk(function(callback) {
2210
2211
  const userProvidedFields = _this._userProvidedFields || {};
2211
2212
 
2212
2213
  applyGlobalMaxTimeMS(this.options, this.model);
2214
+ applyGlobalDiskUse(this.options, this.model);
2213
2215
 
2214
2216
  // Separate options to pass down to `completeMany()` in case we need to
2215
2217
  // set a session on the document
@@ -2228,8 +2230,15 @@ Query.prototype._find = wrapThunk(function(callback) {
2228
2230
  if (this.options.explain) {
2229
2231
  return callback(null, docs);
2230
2232
  }
2231
-
2232
2233
  if (!mongooseOptions.populate) {
2234
+ const versionKey = _this.schema.options.versionKey;
2235
+ if (mongooseOptions.lean && mongooseOptions.lean.versionKey === false && versionKey) {
2236
+ docs.forEach((doc) => {
2237
+ if (versionKey in doc) {
2238
+ delete doc[versionKey];
2239
+ }
2240
+ });
2241
+ }
2233
2242
  return mongooseOptions.lean ?
2234
2243
  callback(null, docs) :
2235
2244
  completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions, callback);
@@ -2411,6 +2420,12 @@ Query.prototype._completeOne = function(doc, res, callback) {
2411
2420
  }
2412
2421
 
2413
2422
  if (!mongooseOptions.populate) {
2423
+ const versionKey = this.schema.options.versionKey;
2424
+ if (mongooseOptions.lean && mongooseOptions.lean.versionKey === false && versionKey) {
2425
+ if (versionKey in doc) {
2426
+ delete doc[versionKey];
2427
+ }
2428
+ }
2414
2429
  return mongooseOptions.lean ?
2415
2430
  _completeOneLean(doc, res, options, callback) :
2416
2431
  completeOne(model, doc, res, options, projection, userProvidedFields,
@@ -2453,8 +2468,8 @@ Query.prototype._findOne = wrapThunk(function(callback) {
2453
2468
 
2454
2469
  this._applyPaths();
2455
2470
  this._fields = this._castFields(this._fields);
2456
-
2457
2471
  applyGlobalMaxTimeMS(this.options, this.model);
2472
+ applyGlobalDiskUse(this.options, this.model);
2458
2473
 
2459
2474
  // don't pass in the conditions because we already merged them in
2460
2475
  Query.base.findOne.call(this, {}, (err, doc) => {
@@ -2567,6 +2582,7 @@ Query.prototype._count = wrapThunk(function(callback) {
2567
2582
  }
2568
2583
 
2569
2584
  applyGlobalMaxTimeMS(this.options, this.model);
2585
+ applyGlobalDiskUse(this.options, this.model);
2570
2586
 
2571
2587
  const conds = this._conditions;
2572
2588
  const options = this._optionsForExec();
@@ -2594,6 +2610,7 @@ Query.prototype._countDocuments = wrapThunk(function(callback) {
2594
2610
  }
2595
2611
 
2596
2612
  applyGlobalMaxTimeMS(this.options, this.model);
2613
+ applyGlobalDiskUse(this.options, this.model);
2597
2614
 
2598
2615
  const conds = this._conditions;
2599
2616
  const options = this._optionsForExec();
@@ -2814,6 +2831,7 @@ Query.prototype.__distinct = wrapThunk(function __distinct(callback) {
2814
2831
  }
2815
2832
 
2816
2833
  applyGlobalMaxTimeMS(this.options, this.model);
2834
+ applyGlobalDiskUse(this.options, this.model);
2817
2835
 
2818
2836
  const options = this._optionsForExec();
2819
2837
 
package/lib/schema.js CHANGED
@@ -22,6 +22,7 @@ const readPref = require('./driver').get().ReadPreference;
22
22
  const setupTimestamps = require('./helpers/timestamps/setupTimestamps');
23
23
  const utils = require('./utils');
24
24
  const validateRef = require('./helpers/populate/validateRef');
25
+ const util = require('util');
25
26
 
26
27
  let MongooseTypes;
27
28
 
@@ -370,6 +371,9 @@ Schema.prototype._clone = function _clone(Constructor) {
370
371
  if (this.discriminators != null) {
371
372
  s.discriminators = Object.assign({}, this.discriminators);
372
373
  }
374
+ if (this._applyDiscriminators != null) {
375
+ s._applyDiscriminators = Object.assign({}, this._applyDiscriminators);
376
+ }
373
377
 
374
378
  s.aliases = Object.assign({}, this.aliases);
375
379
 
@@ -469,6 +473,11 @@ Schema.prototype.defaultOptions = function(options) {
469
473
  return options;
470
474
  };
471
475
 
476
+ Schema.prototype.discriminator = function(name, schema) {
477
+ this._applyDiscriminators = {};
478
+ this._applyDiscriminators[name] = schema;
479
+ };
480
+
472
481
  /**
473
482
  * Adds key path / schema type pairs to this schema.
474
483
  *
@@ -510,7 +519,6 @@ Schema.prototype.add = function add(obj, prefix) {
510
519
 
511
520
  const keys = Object.keys(obj);
512
521
  const typeKey = this.options.typeKey;
513
-
514
522
  for (const key of keys) {
515
523
  const fullPath = prefix + key;
516
524
  const val = obj[key];
@@ -540,6 +548,25 @@ Schema.prototype.add = function add(obj, prefix) {
540
548
  this.nested[prefix.substring(0, prefix.length - 1)] = true;
541
549
  }
542
550
  this.path(prefix + key, val);
551
+ if (val[0] != null && !(val[0].instanceOfSchema) && utils.isPOJO(val[0].discriminators)) {
552
+ const schemaType = this.path(prefix + key);
553
+ for (const key in val[0].discriminators) {
554
+ schemaType.discriminator(key, val[0].discriminators[key]);
555
+ }
556
+ } else if (val[0] != null && val[0].instanceOfSchema && utils.isPOJO(val[0]._applyDiscriminators)) {
557
+ const applyDiscriminators = val[0]._applyDiscriminators || [];
558
+ const schemaType = this.path(prefix + key);
559
+ for (const disc in applyDiscriminators) {
560
+ schemaType.discriminator(disc, applyDiscriminators[disc]);
561
+ }
562
+ }
563
+ else if (val != null && val.instanceOfSchema && utils.isPOJO(val._applyDiscriminators)) {
564
+ const applyDiscriminators = val._applyDiscriminators || [];
565
+ const schemaType = this.path(prefix + key);
566
+ for (const disc in applyDiscriminators) {
567
+ schemaType.discriminator(disc, applyDiscriminators[disc]);
568
+ }
569
+ }
543
570
  } else if (Object.keys(val).length < 1) {
544
571
  // Special-case: {} always interpreted as Mixed path so leaf at this node
545
572
  if (prefix) {
@@ -569,6 +596,12 @@ Schema.prototype.add = function add(obj, prefix) {
569
596
  this.nested[prefix.substring(0, prefix.length - 1)] = true;
570
597
  }
571
598
  this.path(prefix + key, val);
599
+ if (val != null && !(val.instanceOfSchema) && utils.isPOJO(val.discriminators)) {
600
+ const schemaType = this.path(prefix + key);
601
+ for (const key in val.discriminators) {
602
+ schemaType.discriminator(key, val.discriminators[key]);
603
+ }
604
+ }
572
605
  }
573
606
  }
574
607
  }
@@ -579,6 +612,86 @@ Schema.prototype.add = function add(obj, prefix) {
579
612
  return this;
580
613
  };
581
614
 
615
+ /**
616
+ * Remove an index by name or index specification.
617
+ *
618
+ * removeIndex only removes indexes from your schema object. Does **not** affect the indexes
619
+ * in MongoDB.
620
+ *
621
+ * ####Example:
622
+ *
623
+ * const ToySchema = new Schema({ name: String, color: String, price: Number });
624
+ *
625
+ * // Add a new index on { name, color }
626
+ * ToySchema.index({ name: 1, color: 1 });
627
+ *
628
+ * // Remove index on { name, color }
629
+ * // Keep in mind that order matters! `removeIndex({ color: 1, name: 1 })` won't remove the index
630
+ * ToySchema.removeIndex({ name: 1, color: 1 });
631
+ *
632
+ * // Add an index with a custom name
633
+ * ToySchema.index({ color: 1 }, { name: 'my custom index name' });
634
+ * // Remove index by name
635
+ * ToySchema.removeIndex('my custom index name');
636
+ *
637
+ * @param {Object|string} index name or index specification
638
+ * @return {Schema} the Schema instance
639
+ * @api public
640
+ */
641
+
642
+ Schema.prototype.removeIndex = function removeIndex(index) {
643
+ if (arguments.length > 1) {
644
+ throw new Error('removeIndex() takes only 1 argument');
645
+ }
646
+
647
+ if (typeof index !== 'object' && typeof index !== 'string') {
648
+ throw new Error('removeIndex() may only take either an object or a string as an argument');
649
+ }
650
+
651
+ if (typeof index === 'object') {
652
+ for (let i = this._indexes.length - 1; i >= 0; --i) {
653
+ if (util.isDeepStrictEqual(this._indexes[i][0], index)) {
654
+ this._indexes.splice(i, 1);
655
+ }
656
+ }
657
+ } else {
658
+ for (let i = this._indexes.length - 1; i >= 0; --i) {
659
+ if (this._indexes[i][1] != null && this._indexes[i][1].name === index) {
660
+ this._indexes.splice(i, 1);
661
+ }
662
+ }
663
+ }
664
+
665
+ return this;
666
+ };
667
+
668
+ /**
669
+ * Remove all indexes from this schema.
670
+ *
671
+ * clearIndexes only removes indexes from your schema object. Does **not** affect the indexes
672
+ * in MongoDB.
673
+ *
674
+ * ####Example:
675
+ *
676
+ * const ToySchema = new Schema({ name: String, color: String, price: Number });
677
+ * ToySchema.index({ name: 1 });
678
+ * ToySchema.index({ color: 1 });
679
+ *
680
+ * // Remove all indexes on this schema
681
+ * ToySchema.clearIndexes();
682
+ *
683
+ * ToySchema.indexes(); // []
684
+ *
685
+ * @return {Schema} the Schema instance
686
+ * @api public
687
+ */
688
+
689
+ Schema.prototype.clearIndexes = function clearIndexes() {
690
+ this._indexes.length = 0;
691
+
692
+ return this;
693
+ };
694
+
582
695
  /**
583
696
  * Reserved document keys.
584
697
  *
@@ -6,6 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  const VALID_OPTIONS = Object.freeze([
9
+ 'allowDiskUse',
9
10
  'applyPluginsToChildSchemas',
10
11
  'applyPluginsToDiscriminators',
11
12
  'autoCreate',