mongoose 6.3.9 → 6.4.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/.eslintrc.json +61 -34
- package/lib/connection.js +47 -5
- package/lib/document.js +46 -8
- package/lib/helpers/timestamps/setupTimestamps.js +4 -1
- package/lib/helpers/updateValidators.js +11 -18
- package/lib/index.js +108 -29
- package/lib/model.js +1 -1
- package/lib/query.js +61 -6
- package/lib/schema/documentarray.js +10 -0
- 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/connection.d.ts +5 -0
- package/types/document.d.ts +5 -2
- package/types/expressions.d.ts +2880 -0
- package/types/index.d.ts +35 -6
- package/types/inferschematype.d.ts +155 -0
- package/types/models.d.ts +84 -69
- 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/utility.d.ts +2 -0
package/.eslintrc.json
CHANGED
|
@@ -4,43 +4,70 @@
|
|
|
4
4
|
],
|
|
5
5
|
"ignorePatterns": [
|
|
6
6
|
"docs",
|
|
7
|
+
"tools",
|
|
7
8
|
"dist",
|
|
8
|
-
"
|
|
9
|
+
"website.js",
|
|
10
|
+
"test/files/*",
|
|
11
|
+
"benchmarks"
|
|
9
12
|
],
|
|
10
|
-
"overrides": [
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
13
|
+
"overrides": [
|
|
14
|
+
{
|
|
15
|
+
"files": [
|
|
16
|
+
"**/*.{ts,tsx}"
|
|
17
|
+
],
|
|
18
|
+
"extends": [
|
|
19
|
+
"plugin:@typescript-eslint/eslint-recommended",
|
|
20
|
+
"plugin:@typescript-eslint/recommended"
|
|
21
|
+
],
|
|
22
|
+
"plugins": [
|
|
23
|
+
"@typescript-eslint"
|
|
24
|
+
],
|
|
25
|
+
"rules": {
|
|
26
|
+
"@typescript-eslint/triple-slash-reference": "off",
|
|
27
|
+
"spaced-comment": [
|
|
28
|
+
"error",
|
|
29
|
+
"always",
|
|
30
|
+
{
|
|
31
|
+
"block": {
|
|
32
|
+
"markers": [
|
|
33
|
+
"!"
|
|
34
|
+
],
|
|
35
|
+
"balanced": true
|
|
36
|
+
},
|
|
37
|
+
"markers": [
|
|
38
|
+
"/"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
43
|
+
"@typescript-eslint/ban-types": "off",
|
|
44
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
45
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
46
|
+
"@typescript-eslint/indent": [
|
|
47
|
+
"error",
|
|
48
|
+
2,
|
|
49
|
+
{
|
|
50
|
+
"SwitchCase": 1
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"@typescript-eslint/prefer-optional-chain": "error",
|
|
54
|
+
"@typescript-eslint/brace-style": "error",
|
|
55
|
+
"@typescript-eslint/no-dupe-class-members": "error",
|
|
56
|
+
"@typescript-eslint/no-redeclare": "error",
|
|
57
|
+
"@typescript-eslint/type-annotation-spacing": "error",
|
|
58
|
+
"@typescript-eslint/object-curly-spacing": [
|
|
59
|
+
"error",
|
|
60
|
+
"always"
|
|
61
|
+
],
|
|
62
|
+
"@typescript-eslint/semi": "error",
|
|
63
|
+
"@typescript-eslint/space-before-function-paren": [
|
|
64
|
+
"error",
|
|
65
|
+
"never"
|
|
66
|
+
],
|
|
67
|
+
"@typescript-eslint/space-infix-ops": "off"
|
|
68
|
+
}
|
|
42
69
|
}
|
|
43
|
-
|
|
70
|
+
],
|
|
44
71
|
"plugins": [
|
|
45
72
|
"mocha-no-only"
|
|
46
73
|
],
|
package/lib/connection.js
CHANGED
|
@@ -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
|
}
|
package/lib/document.js
CHANGED
|
@@ -2486,7 +2486,7 @@ function _getPathsToValidate(doc) {
|
|
|
2486
2486
|
const fullPathToSubdoc = subdoc.$__fullPathWithIndexes();
|
|
2487
2487
|
|
|
2488
2488
|
for (const p of paths) {
|
|
2489
|
-
if (p
|
|
2489
|
+
if (p == null || p.startsWith(fullPathToSubdoc + '.')) {
|
|
2490
2490
|
paths.delete(p);
|
|
2491
2491
|
}
|
|
2492
2492
|
}
|
|
@@ -2507,6 +2507,14 @@ function _getPathsToValidate(doc) {
|
|
|
2507
2507
|
continue;
|
|
2508
2508
|
}
|
|
2509
2509
|
|
|
2510
|
+
if (_pathType.$isMongooseDocumentArray) {
|
|
2511
|
+
for (const p of paths) {
|
|
2512
|
+
if (p == null || p.startsWith(_pathType.path + '.')) {
|
|
2513
|
+
paths.delete(p);
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2510
2518
|
// Optimization: if primitive path with no validators, or array of primitives
|
|
2511
2519
|
// with no validators, skip validating this path entirely.
|
|
2512
2520
|
if (!_pathType.caster && _pathType.validators.length === 0) {
|
|
@@ -3145,8 +3153,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3145
3153
|
if (subdoc.$isDocumentArrayElement) {
|
|
3146
3154
|
if (!resetArrays.has(subdoc.parentArray())) {
|
|
3147
3155
|
const array = subdoc.parentArray();
|
|
3148
|
-
|
|
3149
|
-
this.$__.activePaths.init(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
|
|
3156
|
+
this.$__.activePaths.clearPath(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
|
|
3150
3157
|
array[arrayAtomicsBackupSymbol] = array[arrayAtomicsSymbol];
|
|
3151
3158
|
array[arrayAtomicsSymbol] = {};
|
|
3152
3159
|
|
|
@@ -3154,7 +3161,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3154
3161
|
}
|
|
3155
3162
|
} else {
|
|
3156
3163
|
if (subdoc.$parent() === this) {
|
|
3157
|
-
this.$__.activePaths.
|
|
3164
|
+
this.$__.activePaths.clearPath(subdoc.$basePath);
|
|
3158
3165
|
} else if (subdoc.$parent() != null && subdoc.$parent().$isSubdocument) {
|
|
3159
3166
|
// If map path underneath subdocument, may end up with a case where
|
|
3160
3167
|
// map path is modified but parent still needs to be reset. See gh-10295
|
|
@@ -4262,10 +4269,10 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
|
|
|
4262
4269
|
*
|
|
4263
4270
|
* #### Example:
|
|
4264
4271
|
*
|
|
4265
|
-
* Model.findOne().populate('author')
|
|
4266
|
-
*
|
|
4267
|
-
*
|
|
4268
|
-
*
|
|
4272
|
+
* const doc = await Model.findOne().populate('author');
|
|
4273
|
+
*
|
|
4274
|
+
* console.log(doc.author.name); // Dr.Seuss
|
|
4275
|
+
* console.log(doc.populated('author')); // '5144cf8050f071d979c118a7'
|
|
4269
4276
|
*
|
|
4270
4277
|
* If the path was not populated, returns `undefined`.
|
|
4271
4278
|
*
|
|
@@ -4319,6 +4326,37 @@ Document.prototype.populated = function(path, val, options) {
|
|
|
4319
4326
|
|
|
4320
4327
|
Document.prototype.$populated = Document.prototype.populated;
|
|
4321
4328
|
|
|
4329
|
+
/**
|
|
4330
|
+
* Throws an error if a given path is not populated
|
|
4331
|
+
*
|
|
4332
|
+
* #### Example:
|
|
4333
|
+
*
|
|
4334
|
+
* const doc = await Model.findOne().populate('author');
|
|
4335
|
+
*
|
|
4336
|
+
* doc.$assertPopulated('author'); // does not throw
|
|
4337
|
+
* doc.$assertPopulated('other path'); // throws an error
|
|
4338
|
+
*
|
|
4339
|
+
*
|
|
4340
|
+
* @param {String | Array<String>} path
|
|
4341
|
+
* @return {Document} this
|
|
4342
|
+
* @memberOf Document
|
|
4343
|
+
* @instance
|
|
4344
|
+
* @api public
|
|
4345
|
+
*/
|
|
4346
|
+
|
|
4347
|
+
Document.prototype.$assertPopulated = function $assertPopulated(paths) {
|
|
4348
|
+
if (Array.isArray(paths)) {
|
|
4349
|
+
paths.forEach(path => this.$assertPopulated(path));
|
|
4350
|
+
return this;
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4353
|
+
if (!this.$populated(paths)) {
|
|
4354
|
+
throw new MongooseError(`Expected path "${paths}" to be populated`);
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
return this;
|
|
4358
|
+
};
|
|
4359
|
+
|
|
4322
4360
|
/**
|
|
4323
4361
|
* Takes a populated field and returns it to its unpopulated state.
|
|
4324
4362
|
*
|
|
@@ -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
|
|
@@ -273,7 +310,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
|
|
|
273
310
|
Mongoose.prototype.createConnection = function(uri, options, callback) {
|
|
274
311
|
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
275
312
|
|
|
276
|
-
const Connection =
|
|
313
|
+
const Connection = _mongoose.__driver.getConnection();
|
|
277
314
|
const conn = new Connection(_mongoose);
|
|
278
315
|
if (typeof options === 'function') {
|
|
279
316
|
callback = options;
|
|
@@ -467,7 +504,6 @@ Mongoose.prototype.pluralize = function(fn) {
|
|
|
467
504
|
*/
|
|
468
505
|
|
|
469
506
|
Mongoose.prototype.model = function(name, schema, collection, options) {
|
|
470
|
-
|
|
471
507
|
const _mongoose = this instanceof Mongoose ? this : mongoose;
|
|
472
508
|
|
|
473
509
|
if (typeof schema === 'string') {
|
|
@@ -684,7 +720,7 @@ Mongoose.prototype.__defineGetter__('connection', function() {
|
|
|
684
720
|
});
|
|
685
721
|
|
|
686
722
|
Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
687
|
-
if (v instanceof
|
|
723
|
+
if (v instanceof this.__driver.getConnection()) {
|
|
688
724
|
this.connections[0] = v;
|
|
689
725
|
this.models = v.models;
|
|
690
726
|
}
|
|
@@ -713,18 +749,6 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
|
713
749
|
|
|
714
750
|
Mongoose.prototype.connections;
|
|
715
751
|
|
|
716
|
-
/*!
|
|
717
|
-
* Connection
|
|
718
|
-
*/
|
|
719
|
-
|
|
720
|
-
const Connection = driver.get().getConnection();
|
|
721
|
-
|
|
722
|
-
/*!
|
|
723
|
-
* Collection
|
|
724
|
-
*/
|
|
725
|
-
|
|
726
|
-
const Collection = driver.get().Collection;
|
|
727
|
-
|
|
728
752
|
/**
|
|
729
753
|
* The Mongoose Aggregate constructor
|
|
730
754
|
*
|
|
@@ -741,7 +765,14 @@ Mongoose.prototype.Aggregate = Aggregate;
|
|
|
741
765
|
* @api public
|
|
742
766
|
*/
|
|
743
767
|
|
|
744
|
-
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
|
+
});
|
|
745
776
|
|
|
746
777
|
/**
|
|
747
778
|
* The Mongoose [Connection](#connection_Connection) constructor
|
|
@@ -752,7 +783,18 @@ Mongoose.prototype.Collection = Collection;
|
|
|
752
783
|
* @api public
|
|
753
784
|
*/
|
|
754
785
|
|
|
755
|
-
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
|
+
});
|
|
756
798
|
|
|
757
799
|
/**
|
|
758
800
|
* The Mongoose version
|
|
@@ -1178,6 +1220,43 @@ Mongoose.prototype._promiseOrCallback = function(callback, fn, ee) {
|
|
|
1178
1220
|
return promiseOrCallback(callback, fn, ee, this.Promise);
|
|
1179
1221
|
};
|
|
1180
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
|
+
|
|
1181
1260
|
/*!
|
|
1182
1261
|
* The exports object is an instance of Mongoose.
|
|
1183
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
|
|