mongoose 6.6.7 → 6.7.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/dist/browser.umd.js +1 -1
- package/lib/aggregate.js +28 -8
- package/lib/document.js +42 -0
- package/lib/error/setOptionError.js +101 -0
- package/lib/error/validation.js +3 -23
- package/lib/helpers/error/combinePathErrors.js +22 -0
- package/lib/helpers/model/discriminator.js +7 -3
- package/lib/index.js +54 -18
- package/lib/model.js +14 -2
- package/lib/schema/index.js +2 -0
- package/lib/schema/uuid.js +329 -0
- package/lib/schema.js +82 -9
- package/package.json +2 -2
- package/types/aggregate.d.ts +3 -0
- package/types/expressions.d.ts +22 -0
- package/types/index.d.ts +7 -0
- package/types/inferschematype.d.ts +33 -24
- package/types/models.d.ts +9 -2
- package/types/pipelinestage.d.ts +11 -0
- package/types/schematypes.d.ts +1 -1
package/lib/aggregate.js
CHANGED
|
@@ -111,11 +111,11 @@ Aggregate.prototype.model = function(model) {
|
|
|
111
111
|
this._model = model;
|
|
112
112
|
if (model.schema != null) {
|
|
113
113
|
if (this.options.readPreference == null &&
|
|
114
|
-
|
|
114
|
+
model.schema.options.read != null) {
|
|
115
115
|
this.options.readPreference = model.schema.options.read;
|
|
116
116
|
}
|
|
117
117
|
if (this.options.collation == null &&
|
|
118
|
-
|
|
118
|
+
model.schema.options.collation != null) {
|
|
119
119
|
this.options.collation = model.schema.options.collation;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -158,7 +158,7 @@ Aggregate.prototype.append = function() {
|
|
|
158
158
|
* Requires MongoDB v3.4+ to work
|
|
159
159
|
*
|
|
160
160
|
* #### Example:
|
|
161
|
-
|
|
161
|
+
*
|
|
162
162
|
* // adding new fields based on existing fields
|
|
163
163
|
* aggregate.addFields({
|
|
164
164
|
* newField: '$b.nested'
|
|
@@ -328,6 +328,28 @@ Aggregate.prototype.project = function(arg) {
|
|
|
328
328
|
* @api public
|
|
329
329
|
*/
|
|
330
330
|
|
|
331
|
+
/**
|
|
332
|
+
* Appends a new $fill operator to this aggregate pipeline.
|
|
333
|
+
*
|
|
334
|
+
* #### Example:
|
|
335
|
+
*
|
|
336
|
+
* aggregate.fill({
|
|
337
|
+
* output: {
|
|
338
|
+
* bootsSold: { value: 0 },
|
|
339
|
+
* sandalsSold: { value: 0 },
|
|
340
|
+
* sneakersSold: { value: 0 }
|
|
341
|
+
* }
|
|
342
|
+
* });
|
|
343
|
+
*
|
|
344
|
+
* @see $fill https://www.mongodb.com/docs/manual/reference/operator/aggregation/fill/
|
|
345
|
+
* @method fill
|
|
346
|
+
* @memberOf Aggregate
|
|
347
|
+
* @instance
|
|
348
|
+
* @param {Object} arg $fill operator contents
|
|
349
|
+
* @return {Aggregate}
|
|
350
|
+
* @api public
|
|
351
|
+
*/
|
|
352
|
+
|
|
331
353
|
/**
|
|
332
354
|
* Appends a new $geoNear operator to this aggregate pipeline.
|
|
333
355
|
*
|
|
@@ -366,7 +388,7 @@ Aggregate.prototype.near = function(arg) {
|
|
|
366
388
|
* define methods
|
|
367
389
|
*/
|
|
368
390
|
|
|
369
|
-
'group match skip limit out densify'.split(' ').forEach(function($operator) {
|
|
391
|
+
'group match skip limit out densify fill'.split(' ').forEach(function($operator) {
|
|
370
392
|
Aggregate.prototype[$operator] = function(arg) {
|
|
371
393
|
const op = {};
|
|
372
394
|
op['$' + $operator] = arg;
|
|
@@ -702,7 +724,7 @@ Aggregate.prototype.readConcern = function(level) {
|
|
|
702
724
|
Aggregate.prototype.redact = function(expression, thenExpr, elseExpr) {
|
|
703
725
|
if (arguments.length === 3) {
|
|
704
726
|
if ((typeof thenExpr === 'string' && !validRedactStringValues.has(thenExpr)) ||
|
|
705
|
-
|
|
727
|
+
(typeof elseExpr === 'string' && !validRedactStringValues.has(elseExpr))) {
|
|
706
728
|
throw new Error('If thenExpr or elseExpr is string, it must be either $$DESCEND, $$PRUNE or $$KEEP');
|
|
707
729
|
}
|
|
708
730
|
|
|
@@ -1099,9 +1121,7 @@ Aggregate.prototype.catch = function(reject) {
|
|
|
1099
1121
|
|
|
1100
1122
|
if (Symbol.asyncIterator != null) {
|
|
1101
1123
|
Aggregate.prototype[Symbol.asyncIterator] = function() {
|
|
1102
|
-
return this.cursor({ useMongooseAggCursor: true }).
|
|
1103
|
-
transformNull().
|
|
1104
|
-
_transformForAsyncIterator();
|
|
1124
|
+
return this.cursor({ useMongooseAggCursor: true }).transformNull()._transformForAsyncIterator();
|
|
1105
1125
|
};
|
|
1106
1126
|
}
|
|
1107
1127
|
|
package/lib/document.js
CHANGED
|
@@ -948,6 +948,48 @@ Document.prototype.$session = function $session(session) {
|
|
|
948
948
|
return session;
|
|
949
949
|
};
|
|
950
950
|
|
|
951
|
+
/**
|
|
952
|
+
* Getter/setter around whether this document will apply timestamps by
|
|
953
|
+
* default when using `save()` and `bulkSave()`.
|
|
954
|
+
*
|
|
955
|
+
* #### Example:
|
|
956
|
+
*
|
|
957
|
+
* const TestModel = mongoose.model('Test', new Schema({ name: String }, { timestamps: true }));
|
|
958
|
+
* const doc = new TestModel({ name: 'John Smith' });
|
|
959
|
+
*
|
|
960
|
+
* doc.$timestamps(); // true
|
|
961
|
+
*
|
|
962
|
+
* doc.$timestamps(false);
|
|
963
|
+
* await doc.save(); // Does **not** apply timestamps
|
|
964
|
+
*
|
|
965
|
+
* @param {Boolean} [value] overwrite the current session
|
|
966
|
+
* @return {Document|boolean|undefined} When used as a getter (no argument), a boolean will be returned indicating the timestamps option state or if unset "undefined" will be used, otherwise will return "this"
|
|
967
|
+
* @method $timestamps
|
|
968
|
+
* @api public
|
|
969
|
+
* @memberOf Document
|
|
970
|
+
*/
|
|
971
|
+
|
|
972
|
+
Document.prototype.$timestamps = function $timestamps(value) {
|
|
973
|
+
if (arguments.length === 0) {
|
|
974
|
+
if (this.$__.timestamps != null) {
|
|
975
|
+
return this.$__.timestamps;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
if (this.$__schema) {
|
|
979
|
+
return this.$__schema.options.timestamps;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return undefined;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
const currentValue = this.$timestamps();
|
|
986
|
+
if (value !== currentValue) {
|
|
987
|
+
this.$__.timestamps = value;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
return this;
|
|
991
|
+
};
|
|
992
|
+
|
|
951
993
|
/**
|
|
952
994
|
* Overwrite all values in this document with the values of `obj`, except
|
|
953
995
|
* for immutable properties. Behaves similarly to `set()`, except for it
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Module requirements
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const MongooseError = require('./mongooseError');
|
|
8
|
+
const util = require('util');
|
|
9
|
+
const combinePathErrors = require('../helpers/error/combinePathErrors');
|
|
10
|
+
|
|
11
|
+
class SetOptionError extends MongooseError {
|
|
12
|
+
/**
|
|
13
|
+
* Mongoose.set Error
|
|
14
|
+
*
|
|
15
|
+
* @api private
|
|
16
|
+
* @inherits MongooseError
|
|
17
|
+
*/
|
|
18
|
+
constructor() {
|
|
19
|
+
super('');
|
|
20
|
+
|
|
21
|
+
this.errors = {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Console.log helper
|
|
26
|
+
*/
|
|
27
|
+
toString() {
|
|
28
|
+
return combinePathErrors(this);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* inspect helper
|
|
33
|
+
* @api private
|
|
34
|
+
*/
|
|
35
|
+
inspect() {
|
|
36
|
+
return Object.assign(new Error(this.message), this);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* add message
|
|
41
|
+
* @param {String} key
|
|
42
|
+
* @param {String|Error} error
|
|
43
|
+
* @api private
|
|
44
|
+
*/
|
|
45
|
+
addError(key, error) {
|
|
46
|
+
if (error instanceof SetOptionError) {
|
|
47
|
+
const { errors } = error;
|
|
48
|
+
for (const optionKey of Object.keys(errors)) {
|
|
49
|
+
this.addError(optionKey, errors[optionKey]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.errors[key] = error;
|
|
56
|
+
this.message = combinePathErrors(this);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if (util.inspect.custom) {
|
|
62
|
+
// Avoid Node deprecation warning DEP0079
|
|
63
|
+
SetOptionError.prototype[util.inspect.custom] = SetOptionError.prototype.inspect;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Helper for JSON.stringify
|
|
68
|
+
* Ensure `name` and `message` show up in toJSON output re: gh-9847
|
|
69
|
+
* @api private
|
|
70
|
+
*/
|
|
71
|
+
Object.defineProperty(SetOptionError.prototype, 'toJSON', {
|
|
72
|
+
enumerable: false,
|
|
73
|
+
writable: false,
|
|
74
|
+
configurable: true,
|
|
75
|
+
value: function() {
|
|
76
|
+
return Object.assign({}, this, { name: this.name, message: this.message });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
Object.defineProperty(SetOptionError.prototype, 'name', {
|
|
82
|
+
value: 'SetOptionError'
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
class SetOptionInnerError extends MongooseError {
|
|
86
|
+
/**
|
|
87
|
+
* Error for the "errors" array in "SetOptionError" with consistent message
|
|
88
|
+
* @param {String} key
|
|
89
|
+
*/
|
|
90
|
+
constructor(key) {
|
|
91
|
+
super(`"${key}" is not a valid option to set`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
SetOptionError.SetOptionInnerError = SetOptionInnerError;
|
|
96
|
+
|
|
97
|
+
/*!
|
|
98
|
+
* Module exports
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
module.exports = SetOptionError;
|
package/lib/error/validation.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const MongooseError = require('./mongooseError');
|
|
8
8
|
const getConstructorName = require('../helpers/getConstructorName');
|
|
9
9
|
const util = require('util');
|
|
10
|
+
const combinePathErrors = require('../helpers/error/combinePathErrors');
|
|
10
11
|
|
|
11
12
|
class ValidationError extends MongooseError {
|
|
12
13
|
/**
|
|
@@ -38,7 +39,7 @@ class ValidationError extends MongooseError {
|
|
|
38
39
|
* Console.log helper
|
|
39
40
|
*/
|
|
40
41
|
toString() {
|
|
41
|
-
return this.name + ': ' +
|
|
42
|
+
return this.name + ': ' + combinePathErrors(this);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -66,7 +67,7 @@ class ValidationError extends MongooseError {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
this.errors[path] = error;
|
|
69
|
-
this.message = this._message + ': ' +
|
|
70
|
+
this.message = this._message + ': ' + combinePathErrors(this);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -95,27 +96,6 @@ Object.defineProperty(ValidationError.prototype, 'name', {
|
|
|
95
96
|
value: 'ValidationError'
|
|
96
97
|
});
|
|
97
98
|
|
|
98
|
-
/*!
|
|
99
|
-
* ignore
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
function _generateMessage(err) {
|
|
103
|
-
const keys = Object.keys(err.errors || {});
|
|
104
|
-
const len = keys.length;
|
|
105
|
-
const msgs = [];
|
|
106
|
-
let key;
|
|
107
|
-
|
|
108
|
-
for (let i = 0; i < len; ++i) {
|
|
109
|
-
key = keys[i];
|
|
110
|
-
if (err === err.errors[key]) {
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
msgs.push(key + ': ' + err.errors[key].message);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return msgs.join(', ');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
99
|
/*!
|
|
120
100
|
* Module exports
|
|
121
101
|
*/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* ignore
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports = function combinePathErrors(err) {
|
|
8
|
+
const keys = Object.keys(err.errors || {});
|
|
9
|
+
const len = keys.length;
|
|
10
|
+
const msgs = [];
|
|
11
|
+
let key;
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < len; ++i) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (err === err.errors[key]) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
msgs.push(key + ': ' + err.errors[key].message);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return msgs.join(', ');
|
|
22
|
+
};
|
|
@@ -19,11 +19,13 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
|
|
19
19
|
* ignore
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
|
|
22
|
+
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks) {
|
|
23
23
|
if (!(schema && schema.instanceOfSchema)) {
|
|
24
24
|
throw new Error('You must pass a valid discriminator Schema');
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
mergeHooks = mergeHooks == null ? true : mergeHooks;
|
|
28
|
+
|
|
27
29
|
if (model.schema.discriminatorMapping &&
|
|
28
30
|
!model.schema.discriminatorMapping.isRoot) {
|
|
29
31
|
throw new Error('Discriminator "' + name +
|
|
@@ -32,7 +34,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
|
|
|
32
34
|
|
|
33
35
|
if (applyPlugins) {
|
|
34
36
|
const applyPluginsToDiscriminators = get(model.base,
|
|
35
|
-
'options.applyPluginsToDiscriminators', false);
|
|
37
|
+
'options.applyPluginsToDiscriminators', false) || !mergeHooks;
|
|
36
38
|
// Even if `applyPluginsToDiscriminators` isn't set, we should still apply
|
|
37
39
|
// global plugins to schemas embedded in the discriminator schema (gh-7370)
|
|
38
40
|
model.base._applyPlugins(schema, {
|
|
@@ -179,7 +181,9 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
|
|
|
179
181
|
schema.options._id = _id;
|
|
180
182
|
}
|
|
181
183
|
schema.options.id = id;
|
|
182
|
-
|
|
184
|
+
if (mergeHooks) {
|
|
185
|
+
schema.s.hooks = model.schema.s.hooks.merge(schema.s.hooks);
|
|
186
|
+
}
|
|
183
187
|
|
|
184
188
|
schema.plugins = Array.prototype.slice.call(baseSchema.plugins);
|
|
185
189
|
schema.callQueue = baseSchema.callQueue.concat(schema.callQueue);
|
package/lib/index.js
CHANGED
|
@@ -37,6 +37,7 @@ const trusted = require('./helpers/query/trusted').trusted;
|
|
|
37
37
|
const sanitizeFilter = require('./helpers/query/sanitizeFilter');
|
|
38
38
|
const isBsonType = require('./helpers/isBsonType');
|
|
39
39
|
const MongooseError = require('./error/mongooseError');
|
|
40
|
+
const SetOptionError = require('./error/setOptionError');
|
|
40
41
|
|
|
41
42
|
const defaultMongooseSymbol = Symbol.for('mongoose:default');
|
|
42
43
|
|
|
@@ -182,6 +183,9 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
|
182
183
|
/**
|
|
183
184
|
* Sets mongoose options
|
|
184
185
|
*
|
|
186
|
+
* `key` can be used a object to set multiple options at once.
|
|
187
|
+
* If a error gets thrown for one option, other options will still be evaluated.
|
|
188
|
+
*
|
|
185
189
|
* #### Example:
|
|
186
190
|
*
|
|
187
191
|
* mongoose.set('test', value) // sets the 'test' option to `value`
|
|
@@ -190,6 +194,8 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
|
190
194
|
*
|
|
191
195
|
* mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {}); // use custom function to log collection methods + arguments
|
|
192
196
|
*
|
|
197
|
+
* mongoose.set({ debug: true, autoIndex: false }); // set multiple options at once
|
|
198
|
+
*
|
|
193
199
|
* Currently supported options are:
|
|
194
200
|
* - 'applyPluginsToChildSchemas': `true` by default. Set to false to skip applying global plugins to child schemas
|
|
195
201
|
* - '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.
|
|
@@ -213,36 +219,66 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
|
213
219
|
* - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
|
|
214
220
|
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
|
|
215
221
|
*
|
|
216
|
-
* @param {String} key
|
|
217
|
-
* @param {String|Function|Boolean} value
|
|
222
|
+
* @param {String|Object} key The name of the option or a object of multiple key-value pairs
|
|
223
|
+
* @param {String|Function|Boolean} value The value of the option, unused if "key" is a object
|
|
224
|
+
* @returns {Mongoose} The used Mongoose instnace
|
|
218
225
|
* @api public
|
|
219
226
|
*/
|
|
220
227
|
|
|
221
228
|
Mongoose.prototype.set = function(key, value) {
|
|
222
229
|
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
223
230
|
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
if (arguments.length === 1 && typeof key !== 'object') {
|
|
232
|
+
if (VALID_OPTIONS.indexOf(key) === -1) {
|
|
233
|
+
const error = new SetOptionError();
|
|
234
|
+
error.addError(key, new SetOptionError.SetOptionInnerError(key));
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
227
237
|
|
|
228
|
-
if (arguments.length === 1) {
|
|
229
238
|
return _mongoose.options[key];
|
|
230
239
|
}
|
|
231
240
|
|
|
232
|
-
|
|
241
|
+
let options = {};
|
|
233
242
|
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
243
|
+
if (arguments.length === 2) {
|
|
244
|
+
options = { [key]: value };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (arguments.length === 1 && typeof key === 'object') {
|
|
248
|
+
options = key;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// array for errors to collect all errors for all key-value pairs, like ".validate"
|
|
252
|
+
let error = undefined;
|
|
253
|
+
|
|
254
|
+
for (const [optionKey, optionValue] of Object.entries(options)) {
|
|
255
|
+
if (VALID_OPTIONS.indexOf(optionKey) === -1) {
|
|
256
|
+
if (!error) {
|
|
257
|
+
error = new SetOptionError();
|
|
258
|
+
}
|
|
259
|
+
error.addError(optionKey, new SetOptionError.SetOptionInnerError(optionKey));
|
|
260
|
+
continue;
|
|
245
261
|
}
|
|
262
|
+
|
|
263
|
+
_mongoose.options[optionKey] = optionValue;
|
|
264
|
+
|
|
265
|
+
if (optionKey === 'objectIdGetter') {
|
|
266
|
+
if (optionValue) {
|
|
267
|
+
Object.defineProperty(mongoose.Types.ObjectId.prototype, '_id', {
|
|
268
|
+
enumerable: false,
|
|
269
|
+
configurable: true,
|
|
270
|
+
get: function() {
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
} else {
|
|
275
|
+
delete mongoose.Types.ObjectId.prototype._id;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (error) {
|
|
281
|
+
throw error;
|
|
246
282
|
}
|
|
247
283
|
|
|
248
284
|
return _mongoose;
|
package/lib/model.js
CHANGED
|
@@ -511,6 +511,9 @@ Model.prototype.save = function(options, fn) {
|
|
|
511
511
|
if (options.hasOwnProperty('session')) {
|
|
512
512
|
this.$session(options.session);
|
|
513
513
|
}
|
|
514
|
+
if (this.$__.timestamps != null) {
|
|
515
|
+
options.timestamps = this.$__.timestamps;
|
|
516
|
+
}
|
|
514
517
|
this.$__.$versionError = generateVersionError(this, this.modifiedPaths());
|
|
515
518
|
|
|
516
519
|
fn = this.constructor.$handleCallbackError(fn);
|
|
@@ -1211,6 +1214,7 @@ Model.exists = function exists(filter, options, callback) {
|
|
|
1211
1214
|
* @param {String} [options.value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter.
|
|
1212
1215
|
* @param {Boolean} [options.clone=true] By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning.
|
|
1213
1216
|
* @param {Boolean} [options.overwriteModels=false] by default, Mongoose does not allow you to define a discriminator with the same name as another discriminator. Set this to allow overwriting discriminators with the same name.
|
|
1217
|
+
* @param {Boolean} [options.mergeHooks=true] By default, Mongoose merges the base schema's hooks with the discriminator schema's hooks. Set this option to `false` to make Mongoose use the discriminator schema's hooks instead.
|
|
1214
1218
|
* @return {Model} The newly created discriminator model
|
|
1215
1219
|
* @api public
|
|
1216
1220
|
*/
|
|
@@ -1238,7 +1242,7 @@ Model.discriminator = function(name, schema, options) {
|
|
|
1238
1242
|
schema = schema.clone();
|
|
1239
1243
|
}
|
|
1240
1244
|
|
|
1241
|
-
schema = discriminator(this, name, schema, value, true);
|
|
1245
|
+
schema = discriminator(this, name, schema, value, true, options.mergeHooks);
|
|
1242
1246
|
if (this.db.models[name] && !schema.options.overwriteModels) {
|
|
1243
1247
|
throw new OverwriteModelError(name);
|
|
1244
1248
|
}
|
|
@@ -3455,7 +3459,8 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3455
3459
|
if (doc.$__schema.options.versionKey) {
|
|
3456
3460
|
doc[doc.$__schema.options.versionKey] = 0;
|
|
3457
3461
|
}
|
|
3458
|
-
|
|
3462
|
+
const shouldSetTimestamps = (!options || options.timestamps !== false) && doc.initializeTimestamps && (!doc.$__ || doc.$__.timestamps !== false);
|
|
3463
|
+
if (shouldSetTimestamps) {
|
|
3459
3464
|
return doc.initializeTimestamps().toObject(internalToObjectOptions);
|
|
3460
3465
|
}
|
|
3461
3466
|
return doc.toObject(internalToObjectOptions);
|
|
@@ -3696,6 +3701,13 @@ Model.bulkSave = async function(documents, options) {
|
|
|
3696
3701
|
document.$__.saveOptions = document.$__.saveOptions || {};
|
|
3697
3702
|
document.$__.saveOptions.timestamps = options.timestamps;
|
|
3698
3703
|
}
|
|
3704
|
+
} else {
|
|
3705
|
+
for (const document of documents) {
|
|
3706
|
+
if (document.$__.timestamps != null) {
|
|
3707
|
+
document.$__.saveOptions = document.$__.saveOptions || {};
|
|
3708
|
+
document.$__.saveOptions.timestamps = document.$__.timestamps;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3699
3711
|
}
|
|
3700
3712
|
|
|
3701
3713
|
await Promise.all(documents.map(buildPreSavePromise));
|