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/CHANGELOG.md +11 -0
- package/dist/browser.umd.js +2 -1704
- package/lib/aggregate.js +4 -3
- package/lib/cursor/ChangeStream.js +42 -2
- package/lib/cursor/QueryCursor.js +2 -0
- package/lib/error/eachAsyncMultiError.js +41 -0
- package/lib/helpers/cursor/eachAsync.js +44 -12
- package/lib/helpers/model/discriminator.js +1 -3
- package/lib/helpers/query/applyGlobalOption.js +29 -0
- package/lib/index.js +10 -3
- package/lib/model.js +1 -2
- package/lib/query.js +21 -3
- package/lib/schema.js +114 -1
- package/lib/validoptions.js +1 -0
- package/package.json +10 -6
- package/tools/repl.js +2 -1
- package/types/cursor.d.ts +10 -4
- package/types/index.d.ts +181 -57
- package/types/mongooseoptions.d.ts +10 -4
- package/lib/helpers/query/applyGlobalMaxTimeMS.js +0 -15
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/
|
|
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 =>
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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) {
|
|
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)
|
|
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/
|
|
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
|
*
|