mongoose 6.3.8 → 6.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +62 -34
- package/dist/browser.umd.js +68579 -2
- package/lib/connection.js +50 -9
- package/lib/document.js +49 -9
- package/lib/error/disconnected.js +3 -4
- package/lib/helpers/timestamps/setupTimestamps.js +4 -1
- package/lib/helpers/updateValidators.js +11 -18
- package/lib/index.js +108 -33
- package/lib/model.js +1 -1
- package/lib/query.js +61 -6
- package/lib/queryhelpers.js +5 -0
- package/lib/schema/array.js +1 -1
- package/lib/schema/date.js +2 -2
- package/lib/schema/documentarray.js +10 -0
- package/lib/schema/number.js +2 -2
- package/lib/schema/string.js +2 -2
- package/lib/schema.js +3 -4
- package/lib/statemachine.js +13 -0
- package/lib/utils.js +3 -0
- package/lib/validoptions.js +1 -0
- package/package.json +3 -3
- package/tsconfig.json +1 -0
- package/types/aggregate.d.ts +3 -0
- package/types/connection.d.ts +5 -0
- package/types/document.d.ts +13 -4
- package/types/expressions.d.ts +2882 -0
- package/types/index.d.ts +52 -23
- package/types/{indizes.d.ts → indexes.d.ts} +0 -0
- package/types/inferschematype.d.ts +155 -0
- package/types/models.d.ts +85 -70
- package/types/mongooseoptions.d.ts +8 -0
- package/types/pipelinestage.d.ts +76 -80
- package/types/query.d.ts +1 -1
- package/types/schemaoptions.d.ts +21 -3
- package/types/types.d.ts +3 -1
- package/types/utility.d.ts +2 -0
package/lib/connection.js
CHANGED
|
@@ -9,6 +9,7 @@ const EventEmitter = require('events').EventEmitter;
|
|
|
9
9
|
const Schema = require('./schema');
|
|
10
10
|
const STATES = require('./connectionstate');
|
|
11
11
|
const MongooseError = require('./error/index');
|
|
12
|
+
const DisconnectedError = require('./error/disconnected');
|
|
12
13
|
const SyncIndexesError = require('./error/syncIndexes');
|
|
13
14
|
const PromiseProvider = require('./promise_provider');
|
|
14
15
|
const ServerSelectionError = require('./error/serverSelection');
|
|
@@ -565,8 +566,7 @@ function _wrapConnHelper(fn) {
|
|
|
565
566
|
const argsWithoutCb = typeof cb === 'function' ?
|
|
566
567
|
Array.prototype.slice.call(arguments, 0, arguments.length - 1) :
|
|
567
568
|
Array.prototype.slice.call(arguments);
|
|
568
|
-
const disconnectedError = new
|
|
569
|
-
' was disconnected when calling `' + fn.name + '`');
|
|
569
|
+
const disconnectedError = new DisconnectedError(this.id, fn.name);
|
|
570
570
|
|
|
571
571
|
return promiseOrCallback(cb, cb => {
|
|
572
572
|
immediate(() => {
|
|
@@ -697,6 +697,18 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
697
697
|
typeof callback + '"');
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
+
if (this._destroyCalled) {
|
|
701
|
+
const error = 'Connection has been closed and destroyed, and cannot be used for re-opening the connection. ' +
|
|
702
|
+
'Please create a new connection with `mongoose.createConnection()` or `mongoose.connect()`.';
|
|
703
|
+
if (typeof callback === 'function') {
|
|
704
|
+
callback(error);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
throw new MongooseError(error);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
700
712
|
if (this.readyState === STATES.connecting || this.readyState === STATES.connected) {
|
|
701
713
|
if (this._connectionString !== uri) {
|
|
702
714
|
throw new MongooseError('Can\'t call `openUri()` on an active connection with ' +
|
|
@@ -901,6 +913,23 @@ function _setClient(conn, client, options, dbName) {
|
|
|
901
913
|
}
|
|
902
914
|
}
|
|
903
915
|
|
|
916
|
+
Connection.prototype.destroy = function(force, callback) {
|
|
917
|
+
if (typeof force === 'function') {
|
|
918
|
+
callback = force;
|
|
919
|
+
force = false;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if (force != null && typeof force === 'object') {
|
|
923
|
+
this.$wasForceClosed = !!force.force;
|
|
924
|
+
} else {
|
|
925
|
+
this.$wasForceClosed = !!force;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
return promiseOrCallback(callback, cb => {
|
|
929
|
+
this._close(force, true, cb);
|
|
930
|
+
});
|
|
931
|
+
};
|
|
932
|
+
|
|
904
933
|
/**
|
|
905
934
|
* Closes the connection
|
|
906
935
|
*
|
|
@@ -923,7 +952,7 @@ Connection.prototype.close = function(force, callback) {
|
|
|
923
952
|
}
|
|
924
953
|
|
|
925
954
|
return promiseOrCallback(callback, cb => {
|
|
926
|
-
this._close(force, cb);
|
|
955
|
+
this._close(force, false, cb);
|
|
927
956
|
});
|
|
928
957
|
};
|
|
929
958
|
|
|
@@ -931,19 +960,26 @@ Connection.prototype.close = function(force, callback) {
|
|
|
931
960
|
* Handles closing the connection
|
|
932
961
|
*
|
|
933
962
|
* @param {Boolean} force
|
|
963
|
+
* @param {Boolean} destroy
|
|
934
964
|
* @param {Function} callback
|
|
935
965
|
* @api private
|
|
936
966
|
*/
|
|
937
|
-
Connection.prototype._close = function(force, callback) {
|
|
967
|
+
Connection.prototype._close = function(force, destroy, callback) {
|
|
938
968
|
const _this = this;
|
|
939
969
|
const closeCalled = this._closeCalled;
|
|
940
970
|
this._closeCalled = true;
|
|
971
|
+
this._destroyCalled = destroy;
|
|
941
972
|
if (this.client != null) {
|
|
942
973
|
this.client._closeCalled = true;
|
|
974
|
+
this.client._destroyCalled = destroy;
|
|
943
975
|
}
|
|
944
976
|
|
|
977
|
+
const conn = this;
|
|
945
978
|
switch (this.readyState) {
|
|
946
979
|
case STATES.disconnected:
|
|
980
|
+
if (destroy && this.base.connections.indexOf(conn) !== -1) {
|
|
981
|
+
this.base.connections.splice(this.base.connections.indexOf(conn), 1);
|
|
982
|
+
}
|
|
947
983
|
if (closeCalled) {
|
|
948
984
|
callback();
|
|
949
985
|
} else {
|
|
@@ -963,6 +999,9 @@ Connection.prototype._close = function(force, callback) {
|
|
|
963
999
|
if (err) {
|
|
964
1000
|
return callback(err);
|
|
965
1001
|
}
|
|
1002
|
+
if (destroy && _this.base.connections.indexOf(conn) !== -1) {
|
|
1003
|
+
_this.base.connections.splice(_this.base.connections.indexOf(conn), 1);
|
|
1004
|
+
}
|
|
966
1005
|
_this.onClose(force);
|
|
967
1006
|
callback(null);
|
|
968
1007
|
});
|
|
@@ -970,12 +1009,15 @@ Connection.prototype._close = function(force, callback) {
|
|
|
970
1009
|
break;
|
|
971
1010
|
case STATES.connecting:
|
|
972
1011
|
this.once('open', function() {
|
|
973
|
-
_this.close(callback);
|
|
1012
|
+
destroy ? _this.destroy(force, callback) : _this.close(force, callback);
|
|
974
1013
|
});
|
|
975
1014
|
break;
|
|
976
1015
|
|
|
977
1016
|
case STATES.disconnecting:
|
|
978
1017
|
this.once('close', function() {
|
|
1018
|
+
if (destroy && _this.base.connections.indexOf(conn) !== -1) {
|
|
1019
|
+
_this.base.connections.splice(_this.base.connections.indexOf(conn), 1);
|
|
1020
|
+
}
|
|
979
1021
|
callback();
|
|
980
1022
|
});
|
|
981
1023
|
break;
|
|
@@ -1004,7 +1046,7 @@ Connection.prototype.onClose = function(force) {
|
|
|
1004
1046
|
this.emit('close', force);
|
|
1005
1047
|
|
|
1006
1048
|
for (const db of this.otherDbs) {
|
|
1007
|
-
db.close({ force: force, skipCloseClient: true });
|
|
1049
|
+
this._destroyCalled ? db.destroy({ force: force, skipCloseClient: true }) : db.close({ force: force, skipCloseClient: true });
|
|
1008
1050
|
}
|
|
1009
1051
|
};
|
|
1010
1052
|
|
|
@@ -1026,7 +1068,7 @@ Connection.prototype.collection = function(name, options) {
|
|
|
1026
1068
|
};
|
|
1027
1069
|
options = Object.assign({}, defaultOptions, options ? utils.clone(options) : {});
|
|
1028
1070
|
options.$wasForceClosed = this.$wasForceClosed;
|
|
1029
|
-
const Collection = driver.get().Collection;
|
|
1071
|
+
const Collection = this.base && this.base.__driver && this.base.__driver.Collection || driver.get().Collection;
|
|
1030
1072
|
if (!(name in this.collections)) {
|
|
1031
1073
|
this.collections[name] = new Collection(name, this, options);
|
|
1032
1074
|
}
|
|
@@ -1260,8 +1302,7 @@ Connection.prototype.deleteModel = function(name) {
|
|
|
1260
1302
|
*/
|
|
1261
1303
|
|
|
1262
1304
|
Connection.prototype.watch = function(pipeline, options) {
|
|
1263
|
-
const disconnectedError = new
|
|
1264
|
-
' was disconnected when calling `watch()`');
|
|
1305
|
+
const disconnectedError = new DisconnectedError(this.id, 'watch');
|
|
1265
1306
|
|
|
1266
1307
|
const changeStreamThunk = cb => {
|
|
1267
1308
|
immediate(() => {
|
package/lib/document.js
CHANGED
|
@@ -1035,6 +1035,7 @@ Document.prototype.overwrite = function overwrite(obj) {
|
|
|
1035
1035
|
* @param {Any} val the value to set
|
|
1036
1036
|
* @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
|
|
1037
1037
|
* @param {Object} [options] optionally specify options that modify the behavior of the set
|
|
1038
|
+
* @param {Boolean} [options.merge=false] if true, setting a [nested path](/docs/subdocs.html#subdocuments-versus-nested-paths) will merge existing values rather than overwrite the whole object. So `doc.set('nested', { a: 1, b: 2 })` becomes `doc.set('nested.a', 1); doc.set('nested.b', 2);`
|
|
1038
1039
|
* @method $set
|
|
1039
1040
|
* @name $set
|
|
1040
1041
|
* @memberOf Document
|
|
@@ -2486,7 +2487,7 @@ function _getPathsToValidate(doc) {
|
|
|
2486
2487
|
const fullPathToSubdoc = subdoc.$__fullPathWithIndexes();
|
|
2487
2488
|
|
|
2488
2489
|
for (const p of paths) {
|
|
2489
|
-
if (p
|
|
2490
|
+
if (p == null || p.startsWith(fullPathToSubdoc + '.')) {
|
|
2490
2491
|
paths.delete(p);
|
|
2491
2492
|
}
|
|
2492
2493
|
}
|
|
@@ -2507,6 +2508,14 @@ function _getPathsToValidate(doc) {
|
|
|
2507
2508
|
continue;
|
|
2508
2509
|
}
|
|
2509
2510
|
|
|
2511
|
+
if (_pathType.$isMongooseDocumentArray) {
|
|
2512
|
+
for (const p of paths) {
|
|
2513
|
+
if (p == null || p.startsWith(_pathType.path + '.')) {
|
|
2514
|
+
paths.delete(p);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2510
2519
|
// Optimization: if primitive path with no validators, or array of primitives
|
|
2511
2520
|
// with no validators, skip validating this path entirely.
|
|
2512
2521
|
if (!_pathType.caster && _pathType.validators.length === 0) {
|
|
@@ -3145,8 +3154,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3145
3154
|
if (subdoc.$isDocumentArrayElement) {
|
|
3146
3155
|
if (!resetArrays.has(subdoc.parentArray())) {
|
|
3147
3156
|
const array = subdoc.parentArray();
|
|
3148
|
-
|
|
3149
|
-
this.$__.activePaths.init(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
|
|
3157
|
+
this.$__.activePaths.clearPath(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
|
|
3150
3158
|
array[arrayAtomicsBackupSymbol] = array[arrayAtomicsSymbol];
|
|
3151
3159
|
array[arrayAtomicsSymbol] = {};
|
|
3152
3160
|
|
|
@@ -3154,7 +3162,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3154
3162
|
}
|
|
3155
3163
|
} else {
|
|
3156
3164
|
if (subdoc.$parent() === this) {
|
|
3157
|
-
this.$__.activePaths.
|
|
3165
|
+
this.$__.activePaths.clearPath(subdoc.$basePath);
|
|
3158
3166
|
} else if (subdoc.$parent() != null && subdoc.$parent().$isSubdocument) {
|
|
3159
3167
|
// If map path underneath subdocument, may end up with a case where
|
|
3160
3168
|
// map path is modified but parent still needs to be reset. See gh-10295
|
|
@@ -3388,7 +3396,7 @@ Document.prototype.$getAllSubdocs = function() {
|
|
|
3388
3396
|
}, seed);
|
|
3389
3397
|
} else if (val && !Array.isArray(val) && val.$isSingleNested) {
|
|
3390
3398
|
seed = Object.keys(val._doc).reduce(function(seed, path) {
|
|
3391
|
-
return docReducer(val
|
|
3399
|
+
return docReducer(val, seed, path);
|
|
3392
3400
|
}, seed);
|
|
3393
3401
|
seed.push(val);
|
|
3394
3402
|
} else if (val && utils.isMongooseDocumentArray(val)) {
|
|
@@ -4262,10 +4270,10 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
|
|
|
4262
4270
|
*
|
|
4263
4271
|
* #### Example:
|
|
4264
4272
|
*
|
|
4265
|
-
* Model.findOne().populate('author')
|
|
4266
|
-
*
|
|
4267
|
-
*
|
|
4268
|
-
*
|
|
4273
|
+
* const doc = await Model.findOne().populate('author');
|
|
4274
|
+
*
|
|
4275
|
+
* console.log(doc.author.name); // Dr.Seuss
|
|
4276
|
+
* console.log(doc.populated('author')); // '5144cf8050f071d979c118a7'
|
|
4269
4277
|
*
|
|
4270
4278
|
* If the path was not populated, returns `undefined`.
|
|
4271
4279
|
*
|
|
@@ -4319,6 +4327,38 @@ Document.prototype.populated = function(path, val, options) {
|
|
|
4319
4327
|
|
|
4320
4328
|
Document.prototype.$populated = Document.prototype.populated;
|
|
4321
4329
|
|
|
4330
|
+
/**
|
|
4331
|
+
* Throws an error if a given path is not populated
|
|
4332
|
+
*
|
|
4333
|
+
* #### Example:
|
|
4334
|
+
*
|
|
4335
|
+
* const doc = await Model.findOne().populate('author');
|
|
4336
|
+
*
|
|
4337
|
+
* doc.$assertPopulated('author'); // does not throw
|
|
4338
|
+
* doc.$assertPopulated('other path'); // throws an error
|
|
4339
|
+
*
|
|
4340
|
+
*
|
|
4341
|
+
* @param {String|Array<String>} path
|
|
4342
|
+
* @return {Document} this
|
|
4343
|
+
* @memberOf Document
|
|
4344
|
+
* @method $assertPopulated
|
|
4345
|
+
* @instance
|
|
4346
|
+
* @api public
|
|
4347
|
+
*/
|
|
4348
|
+
|
|
4349
|
+
Document.prototype.$assertPopulated = function $assertPopulated(paths) {
|
|
4350
|
+
if (Array.isArray(paths)) {
|
|
4351
|
+
paths.forEach(path => this.$assertPopulated(path));
|
|
4352
|
+
return this;
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4355
|
+
if (!this.$populated(paths)) {
|
|
4356
|
+
throw new MongooseError(`Expected path "${paths}" to be populated`);
|
|
4357
|
+
}
|
|
4358
|
+
|
|
4359
|
+
return this;
|
|
4360
|
+
};
|
|
4361
|
+
|
|
4322
4362
|
/**
|
|
4323
4363
|
* Takes a populated field and returns it to its unpopulated state.
|
|
4324
4364
|
*
|
|
@@ -16,10 +16,9 @@ class DisconnectedError extends MongooseError {
|
|
|
16
16
|
/**
|
|
17
17
|
* @param {String} connectionString
|
|
18
18
|
*/
|
|
19
|
-
constructor(
|
|
20
|
-
super('
|
|
21
|
-
|
|
22
|
-
'`server.reconnectInterval` to something higher.');
|
|
19
|
+
constructor(id, fnName) {
|
|
20
|
+
super('Connection ' + id +
|
|
21
|
+
' was disconnected when calling `' + fnName + '()`');
|
|
23
22
|
}
|
|
24
23
|
}
|
|
25
24
|
|
|
@@ -31,8 +31,11 @@ module.exports = function setupTimestamps(schema, timestamps) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
if (createdAt && !schema.paths[createdAt]) {
|
|
34
|
-
|
|
34
|
+
const baseImmutableCreatedAt = schema.base.get('timestamps.createdAt.immutable');
|
|
35
|
+
const immutable = baseImmutableCreatedAt != null ? baseImmutableCreatedAt : true;
|
|
36
|
+
schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable };
|
|
35
37
|
}
|
|
38
|
+
|
|
36
39
|
schema.add(schemaAdditions);
|
|
37
40
|
|
|
38
41
|
schema.pre('save', function(next) {
|
|
@@ -125,26 +125,19 @@ module.exports = function(query, schema, castedDoc, options, callback) {
|
|
|
125
125
|
validatorsToExecute.push(function(callback) {
|
|
126
126
|
schemaPath.doValidate(v, function(err) {
|
|
127
127
|
if (err) {
|
|
128
|
-
err.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
v.validate(function(err) {
|
|
134
|
-
if (err) {
|
|
135
|
-
if (err.errors) {
|
|
136
|
-
for (const key of Object.keys(err.errors)) {
|
|
137
|
-
const _err = err.errors[key];
|
|
138
|
-
_err.path = updates[i] + '.' + key;
|
|
139
|
-
validationErrors.push(_err);
|
|
140
|
-
}
|
|
141
|
-
} else {
|
|
142
|
-
err.path = updates[i];
|
|
143
|
-
validationErrors.push(err);
|
|
128
|
+
if (err.errors) {
|
|
129
|
+
for (const key of Object.keys(err.errors)) {
|
|
130
|
+
const _err = err.errors[key];
|
|
131
|
+
_err.path = updates[i] + '.' + key;
|
|
132
|
+
validationErrors.push(_err);
|
|
144
133
|
}
|
|
134
|
+
} else {
|
|
135
|
+
err.path = updates[i];
|
|
136
|
+
validationErrors.push(err);
|
|
145
137
|
}
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return callback(null);
|
|
148
141
|
}, context, { updateValidator: true });
|
|
149
142
|
});
|
|
150
143
|
} else {
|
package/lib/index.js
CHANGED
|
@@ -8,6 +8,7 @@ require('./driver').set(require('./drivers/node-mongodb-native'));
|
|
|
8
8
|
|
|
9
9
|
const Document = require('./document');
|
|
10
10
|
const EventEmitter = require('events').EventEmitter;
|
|
11
|
+
const Kareem = require('kareem');
|
|
11
12
|
const Schema = require('./schema');
|
|
12
13
|
const SchemaType = require('./schematype');
|
|
13
14
|
const SchemaTypes = require('./schema/index');
|
|
@@ -35,6 +36,7 @@ const shardingPlugin = require('./plugins/sharding');
|
|
|
35
36
|
const trusted = require('./helpers/query/trusted').trusted;
|
|
36
37
|
const sanitizeFilter = require('./helpers/query/sanitizeFilter');
|
|
37
38
|
const isBsonType = require('./helpers/isBsonType');
|
|
39
|
+
const MongooseError = require('./error/mongooseError');
|
|
38
40
|
|
|
39
41
|
const defaultMongooseSymbol = Symbol.for('mongoose:default');
|
|
40
42
|
|
|
@@ -62,6 +64,7 @@ function Mongoose(options) {
|
|
|
62
64
|
this.connections = [];
|
|
63
65
|
this.models = {};
|
|
64
66
|
this.events = new EventEmitter();
|
|
67
|
+
this.__driver = driver.get();
|
|
65
68
|
// default global options
|
|
66
69
|
this.options = Object.assign({
|
|
67
70
|
pluralization: true,
|
|
@@ -135,6 +138,7 @@ Mongoose.prototype.ConnectionStates = STATES;
|
|
|
135
138
|
* uses to communicate with the database. A driver is a Mongoose-specific interface that defines functions
|
|
136
139
|
* like `find()`.
|
|
137
140
|
*
|
|
141
|
+
* @deprecated
|
|
138
142
|
* @memberOf Mongoose
|
|
139
143
|
* @property driver
|
|
140
144
|
* @api public
|
|
@@ -142,6 +146,36 @@ Mongoose.prototype.ConnectionStates = STATES;
|
|
|
142
146
|
|
|
143
147
|
Mongoose.prototype.driver = driver;
|
|
144
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Overwrites the current driver used by this Mongoose instance. A driver is a
|
|
151
|
+
* Mongoose-specific interface that defines functions like `find()`.
|
|
152
|
+
*
|
|
153
|
+
* @memberOf Mongoose
|
|
154
|
+
* @method setDriver
|
|
155
|
+
* @api public
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
159
|
+
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
160
|
+
|
|
161
|
+
if (_mongoose.__driver === driver) {
|
|
162
|
+
return _mongoose;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const openConnection = _mongoose.connections && _mongoose.connections.find(conn => conn.readyState !== STATES.disconnected);
|
|
166
|
+
if (openConnection) {
|
|
167
|
+
const msg = 'Cannot modify Mongoose driver if a connection is already open. ' +
|
|
168
|
+
'Call `mongoose.disconnect()` before modifying the driver';
|
|
169
|
+
throw new MongooseError(msg);
|
|
170
|
+
}
|
|
171
|
+
_mongoose.__driver = driver;
|
|
172
|
+
|
|
173
|
+
const Connection = driver.getConnection();
|
|
174
|
+
_mongoose.connections = [new Connection(_mongoose)];
|
|
175
|
+
|
|
176
|
+
return _mongoose;
|
|
177
|
+
};
|
|
178
|
+
|
|
145
179
|
/**
|
|
146
180
|
* Sets mongoose options
|
|
147
181
|
*
|
|
@@ -154,23 +188,26 @@ Mongoose.prototype.driver = driver;
|
|
|
154
188
|
* mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {}); // use custom function to log collection methods + arguments
|
|
155
189
|
*
|
|
156
190
|
* Currently supported options are:
|
|
191
|
+
* - 'applyPluginsToChildSchemas': `true` by default. Set to false to skip applying global plugins to child schemas
|
|
192
|
+
* - '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.
|
|
193
|
+
* - '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.
|
|
194
|
+
* - 'autoIndex': `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
|
|
157
195
|
* - '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(', ')})`.
|
|
158
196
|
* - '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.
|
|
159
197
|
* - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
|
|
160
|
-
* - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
|
|
161
|
-
* - '
|
|
162
|
-
* - '
|
|
163
|
-
* - '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.
|
|
164
|
-
* - 'runValidators': false by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
|
|
165
|
-
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
|
|
166
|
-
* - '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()`
|
|
167
|
-
* - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
|
|
168
|
-
* - '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.
|
|
169
|
-
* - '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.
|
|
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 arugments 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
|
+
* - '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`
|
|
170
201
|
* - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
|
|
171
|
-
* - '
|
|
172
|
-
* - '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.
|
|
202
|
+
* - '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.
|
|
173
203
|
* - 'overwriteModels': Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
|
|
204
|
+
* - '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.
|
|
205
|
+
* - 'runValidators': `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
|
|
206
|
+
* - '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.
|
|
207
|
+
* - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
|
|
208
|
+
* - '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.
|
|
209
|
+
* - '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()`
|
|
210
|
+
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
|
|
174
211
|
*
|
|
175
212
|
* @param {String} key
|
|
176
213
|
* @param {String|Function|Boolean} value
|
|
@@ -260,8 +297,6 @@ Mongoose.prototype.get = Mongoose.prototype.set;
|
|
|
260
297
|
* @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
|
|
261
298
|
* @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
|
|
262
299
|
* @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
|
|
263
|
-
* @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
|
|
264
|
-
* @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
|
|
265
300
|
* @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
|
|
266
301
|
* @param {Number} [options.maxPoolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
|
|
267
302
|
* @param {Number} [options.minPoolSize=1] The minimum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
|
|
@@ -275,7 +310,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
|
|
|
275
310
|
Mongoose.prototype.createConnection = function(uri, options, callback) {
|
|
276
311
|
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
277
312
|
|
|
278
|
-
const Connection =
|
|
313
|
+
const Connection = _mongoose.__driver.getConnection();
|
|
279
314
|
const conn = new Connection(_mongoose);
|
|
280
315
|
if (typeof options === 'function') {
|
|
281
316
|
callback = options;
|
|
@@ -323,8 +358,6 @@ Mongoose.prototype.createConnection = function(uri, options, callback) {
|
|
|
323
358
|
* @param {Number} [options.serverSelectionTimeoutMS] If `useUnifiedTopology = true`, the MongoDB driver will try to find a server to send any given operation to, and keep retrying for `serverSelectionTimeoutMS` milliseconds before erroring out. If not set, the MongoDB driver defaults to using `30000` (30 seconds).
|
|
324
359
|
* @param {Number} [options.heartbeatFrequencyMS] If `useUnifiedTopology = true`, the MongoDB driver sends a heartbeat every `heartbeatFrequencyMS` to check on the status of the connection. A heartbeat is subject to `serverSelectionTimeoutMS`, so the MongoDB driver will retry failed heartbeats for up to 30 seconds by default. Mongoose only emits a `'disconnected'` event after a heartbeat has failed, so you may want to decrease this setting to reduce the time between when your server goes down and when Mongoose emits `'disconnected'`. We recommend you do **not** set this setting below 1000, too many heartbeats can lead to performance degradation.
|
|
325
360
|
* @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
|
|
326
|
-
* @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
|
|
327
|
-
* @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
|
|
328
361
|
* @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
|
|
329
362
|
* @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
|
|
330
363
|
* @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
|
|
@@ -471,7 +504,6 @@ Mongoose.prototype.pluralize = function(fn) {
|
|
|
471
504
|
*/
|
|
472
505
|
|
|
473
506
|
Mongoose.prototype.model = function(name, schema, collection, options) {
|
|
474
|
-
|
|
475
507
|
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
476
508
|
|
|
477
509
|
if (typeof schema === 'string') {
|
|
@@ -688,7 +720,7 @@ Mongoose.prototype.__defineGetter__('connection', function() {
|
|
|
688
720
|
});
|
|
689
721
|
|
|
690
722
|
Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
691
|
-
if (v instanceof
|
|
723
|
+
if (v instanceof this.__driver.getConnection()) {
|
|
692
724
|
this.connections[0] = v;
|
|
693
725
|
this.models = v.models;
|
|
694
726
|
}
|
|
@@ -717,18 +749,6 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
|
717
749
|
|
|
718
750
|
Mongoose.prototype.connections;
|
|
719
751
|
|
|
720
|
-
/*!
|
|
721
|
-
* Connection
|
|
722
|
-
*/
|
|
723
|
-
|
|
724
|
-
const Connection = driver.get().getConnection();
|
|
725
|
-
|
|
726
|
-
/*!
|
|
727
|
-
* Collection
|
|
728
|
-
*/
|
|
729
|
-
|
|
730
|
-
const Collection = driver.get().Collection;
|
|
731
|
-
|
|
732
752
|
/**
|
|
733
753
|
* The Mongoose Aggregate constructor
|
|
734
754
|
*
|
|
@@ -745,7 +765,14 @@ Mongoose.prototype.Aggregate = Aggregate;
|
|
|
745
765
|
* @api public
|
|
746
766
|
*/
|
|
747
767
|
|
|
748
|
-
Mongoose.prototype
|
|
768
|
+
Object.defineProperty(Mongoose.prototype, 'Collection', {
|
|
769
|
+
get: function() {
|
|
770
|
+
return this.__driver.Collection;
|
|
771
|
+
},
|
|
772
|
+
set: function(Collection) {
|
|
773
|
+
this.__driver.Collection = Collection;
|
|
774
|
+
}
|
|
775
|
+
});
|
|
749
776
|
|
|
750
777
|
/**
|
|
751
778
|
* The Mongoose [Connection](#connection_Connection) constructor
|
|
@@ -756,7 +783,18 @@ Mongoose.prototype.Collection = Collection;
|
|
|
756
783
|
* @api public
|
|
757
784
|
*/
|
|
758
785
|
|
|
759
|
-
Mongoose.prototype
|
|
786
|
+
Object.defineProperty(Mongoose.prototype, 'Connection', {
|
|
787
|
+
get: function() {
|
|
788
|
+
return this.__driver.getConnection();
|
|
789
|
+
},
|
|
790
|
+
set: function(Connection) {
|
|
791
|
+
if (Connection === this.__driver.getConnection()) {
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
this.__driver.getConnection = () => Connection;
|
|
796
|
+
}
|
|
797
|
+
});
|
|
760
798
|
|
|
761
799
|
/**
|
|
762
800
|
* The Mongoose version
|
|
@@ -1182,6 +1220,43 @@ Mongoose.prototype._promiseOrCallback = function(callback, fn, ee) {
|
|
|
1182
1220
|
return promiseOrCallback(callback, fn, ee, this.Promise);
|
|
1183
1221
|
};
|
|
1184
1222
|
|
|
1223
|
+
/**
|
|
1224
|
+
* Use this function in `pre()` middleware to skip calling the wrapped function.
|
|
1225
|
+
*
|
|
1226
|
+
* ####Example:
|
|
1227
|
+
*
|
|
1228
|
+
* schema.pre('save', function() {
|
|
1229
|
+
* // Will skip executing `save()`, but will execute post hooks as if
|
|
1230
|
+
* // `save()` had executed with the result `{ matchedCount: 0 }`
|
|
1231
|
+
* return mongoose.skipMiddlewareFunction({ matchedCount: 0 });
|
|
1232
|
+
* });
|
|
1233
|
+
*
|
|
1234
|
+
* @method skipMiddlewareFunction
|
|
1235
|
+
* @param {any} result
|
|
1236
|
+
* @api public
|
|
1237
|
+
*/
|
|
1238
|
+
|
|
1239
|
+
Mongoose.prototype.skipMiddlewareFunction = Kareem.skipWrappedFunction;
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* Use this function in `post()` middleware to replace the result
|
|
1243
|
+
*
|
|
1244
|
+
* ####Example:
|
|
1245
|
+
*
|
|
1246
|
+
* schema.post('find', function(res) {
|
|
1247
|
+
* // Normally you have to modify `res` in place. But with
|
|
1248
|
+
* // `overwriteMiddlewarResult()`, you can make `find()` return a
|
|
1249
|
+
* // completely different value.
|
|
1250
|
+
* return mongoose.overwriteMiddlewareResult(res.filter(doc => !doc.isDeleted));
|
|
1251
|
+
* });
|
|
1252
|
+
*
|
|
1253
|
+
* @method overwriteMiddlewareResult
|
|
1254
|
+
* @param {any} result
|
|
1255
|
+
* @api public
|
|
1256
|
+
*/
|
|
1257
|
+
|
|
1258
|
+
Mongoose.prototype.overwriteMiddlewareResult = Kareem.overwriteResult;
|
|
1259
|
+
|
|
1185
1260
|
/*!
|
|
1186
1261
|
* The exports object is an instance of Mongoose.
|
|
1187
1262
|
*
|
package/lib/model.js
CHANGED
|
@@ -4281,7 +4281,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
|
|
|
4281
4281
|
|
|
4282
4282
|
for (const path of paths) {
|
|
4283
4283
|
const schemaType = schema.path(path);
|
|
4284
|
-
if (!schemaType || !schemaType.$isMongooseArray) {
|
|
4284
|
+
if (!schemaType || !schemaType.$isMongooseArray || schemaType.$isMongooseDocumentArray) {
|
|
4285
4285
|
continue;
|
|
4286
4286
|
}
|
|
4287
4287
|
|