mongoose 5.4.0 → 5.4.4
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/History.md +41 -0
- package/lib/cast.js +4 -3
- package/lib/connection.js +6 -0
- package/lib/document.js +29 -18
- package/lib/helpers/document/compile.js +5 -3
- package/lib/helpers/get.js +9 -0
- package/lib/helpers/model/applyHooks.js +22 -12
- package/lib/helpers/model/discriminator.js +6 -3
- package/lib/helpers/once.js +12 -0
- package/lib/helpers/query/castFilterPath.js +54 -0
- package/lib/helpers/query/selectPopulatedFields.js +4 -3
- package/lib/helpers/query/wrapThunk.js +18 -0
- package/lib/helpers/symbols.js +5 -1
- package/lib/helpers/update/castArrayFilters.js +62 -0
- package/lib/index.js +52 -14
- package/lib/model.js +52 -39
- package/lib/plugins/sharding.js +11 -4
- package/lib/query.js +90 -38
- package/lib/schema/boolean.js +9 -7
- package/lib/schema/documentarray.js +38 -0
- package/lib/schema/embedded.js +1 -0
- package/lib/schema/map.js +3 -3
- package/lib/schema/string.js +7 -6
- package/lib/schema/symbols.js +3 -1
- package/lib/schema.js +55 -17
- package/lib/schematype.js +36 -2
- package/lib/types/documentarray.js +5 -1
- package/lib/types/objectid.js +3 -0
- package/lib/utils.js +9 -4
- package/package.json +2 -3
package/History.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
5.4.4 / 2019-01-14
|
|
2
|
+
==================
|
|
3
|
+
* fix(query): run casting on arrayFilters option #7079
|
|
4
|
+
* fix(document): support skipping timestamps on save() with `save({ timestamps: false })` #7357
|
|
5
|
+
* fix(model): apply custom where on `Document#remove()` so we attach the shardKey #7393
|
|
6
|
+
* docs(mongoose): document `mongoose.connections` #7338
|
|
7
|
+
|
|
8
|
+
5.4.3 / 2019-01-09
|
|
9
|
+
==================
|
|
10
|
+
* fix(populate): handle `count` option when using `Document#populate()` on a virtual #7380
|
|
11
|
+
* fix(connection): set connection state to DISCONNECTED if replica set has no primary #7330
|
|
12
|
+
* fix(mongoose): apply global plugins to schemas nested underneath embedded discriminators #7370
|
|
13
|
+
* fix(document): make modifiedPaths() return nested paths 1 level down on initial set #7313
|
|
14
|
+
* fix(plugins): ensure sharding plugin works even if ObjectId has a `valueOf()` #7353
|
|
15
|
+
|
|
16
|
+
5.4.2 / 2019-01-03
|
|
17
|
+
==================
|
|
18
|
+
* fix(document): ensure Document#updateOne() returns a query but still calls hooks #7366
|
|
19
|
+
* fix(query): allow explicitly projecting out populated paths that are automatically projected in #7383
|
|
20
|
+
* fix(document): support setting `flattenMaps` option for `toObject()` and `toJSON()` at schema level #7274
|
|
21
|
+
* fix(query): handle merging objectids with `.where()` #7360
|
|
22
|
+
* fix(schema): copy `.base` when cloning #7377
|
|
23
|
+
* docs: remove links to plugins.mongoosejs.com in favor of plugins.mongoosejs.io #7364
|
|
24
|
+
|
|
25
|
+
5.4.1 / 2018-12-26
|
|
26
|
+
==================
|
|
27
|
+
* fix(document): ensure doc array defaults get casted #7337
|
|
28
|
+
* fix(document): make `save()` not crash if nested doc has a property 'get' #7316
|
|
29
|
+
* fix(schema): allow using Schema.Types.Map as well as Map to declare a map type #7305
|
|
30
|
+
* fix(map): make set after init mark correct path as modified #7321
|
|
31
|
+
* fix(mongoose): don't recompile model if same collection and schema passed in to `mongoose.model()` #5767
|
|
32
|
+
* fix(schema): improve error message when type is invalid #7303
|
|
33
|
+
* fix(schema): add `populated` to reserved property names #7317
|
|
34
|
+
* fix(model): don't run built-in middleware on custom methods and ensure timestamp hooks don't run if children don't have timestamps set #7342
|
|
35
|
+
* docs(schematypes): clarify that you can add arbitrary options to a SchemaType #7340
|
|
36
|
+
* docs(mongoose): clarify that passing same name+schema to `mongoose.model()` returns the model #5767
|
|
37
|
+
* docs(index): add useNewUrlParser to example #7368 [JIBIN-P](https://github.com/JIBIN-P)
|
|
38
|
+
* docs(connection): add useNewUrlParser to examples #7362 [JIBIN-P](https://github.com/JIBIN-P)
|
|
39
|
+
* docs(discriminators): add back missing example from 'recursive embedded discriminators section' #7349
|
|
40
|
+
* docs(schema): improve docs for string and boolean cast() #7351
|
|
41
|
+
|
|
1
42
|
5.4.0 / 2018-12-14
|
|
2
43
|
==================
|
|
3
44
|
* feat(schematype): add `SchemaType.get()`, custom getters across all instances of a schematype #6912
|
package/lib/cast.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
const StrictModeError = require('./error/strict');
|
|
8
8
|
const Types = require('./schema/index');
|
|
9
9
|
const castTextSearch = require('./schema/operators/text');
|
|
10
|
-
const get = require('
|
|
10
|
+
const get = require('./helpers/get');
|
|
11
11
|
const util = require('util');
|
|
12
12
|
const utils = require('./utils');
|
|
13
13
|
|
|
@@ -82,6 +82,7 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
82
82
|
const pathLastHalf = split.slice(j).join('.');
|
|
83
83
|
const _schematype = schema.path(pathFirstHalf);
|
|
84
84
|
const discriminatorKey = get(_schematype, 'schema.options.discriminatorKey');
|
|
85
|
+
|
|
85
86
|
// gh-6027: if we haven't found the schematype but this path is
|
|
86
87
|
// underneath an embedded discriminator and the embedded discriminator
|
|
87
88
|
// key is in the query, use the embedded discriminator schema
|
|
@@ -90,7 +91,7 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
90
91
|
discriminatorKey != null &&
|
|
91
92
|
pathLastHalf !== discriminatorKey) {
|
|
92
93
|
const discriminatorVal = get(obj, pathFirstHalf + '.' + discriminatorKey);
|
|
93
|
-
if (discriminatorVal) {
|
|
94
|
+
if (discriminatorVal != null) {
|
|
94
95
|
schematype = _schematype.schema.discriminators[discriminatorVal].
|
|
95
96
|
path(pathLastHalf);
|
|
96
97
|
}
|
|
@@ -336,4 +337,4 @@ function _cast(val, numbertype, context) {
|
|
|
336
337
|
}
|
|
337
338
|
}
|
|
338
339
|
}
|
|
339
|
-
}
|
|
340
|
+
}
|
package/lib/connection.js
CHANGED
|
@@ -549,6 +549,12 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
549
549
|
// Implicitly emits 'disconnected'
|
|
550
550
|
_this.readyState = STATES.disconnected;
|
|
551
551
|
});
|
|
552
|
+
client.on('left', function() {
|
|
553
|
+
if (_this.readyState === STATES.connected &&
|
|
554
|
+
get(db, 's.topology.s.coreTopology.s.replicaSetState.topologyType') === 'ReplicaSetNoPrimary') {
|
|
555
|
+
_this.readyState = STATES.disconnected;
|
|
556
|
+
}
|
|
557
|
+
});
|
|
552
558
|
db.on('timeout', function() {
|
|
553
559
|
_this.emit('timeout');
|
|
554
560
|
});
|
package/lib/document.js
CHANGED
|
@@ -33,6 +33,7 @@ const deepEqual = utils.deepEqual;
|
|
|
33
33
|
const isMongooseObject = utils.isMongooseObject;
|
|
34
34
|
|
|
35
35
|
const documentArrayParent = require('./helpers/symbols').documentArrayParent;
|
|
36
|
+
const getSymbol = require('./helpers/symbols').getSymbol;
|
|
36
37
|
|
|
37
38
|
let DocumentArray;
|
|
38
39
|
let MongooseArray;
|
|
@@ -239,10 +240,9 @@ function $__hasIncludedChildren(fields) {
|
|
|
239
240
|
* ignore
|
|
240
241
|
*/
|
|
241
242
|
|
|
242
|
-
function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip
|
|
243
|
+
function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
|
|
243
244
|
const paths = Object.keys(doc.schema.paths);
|
|
244
245
|
const plen = paths.length;
|
|
245
|
-
const init = options && 'isNew' in options ? options.isNew : false;
|
|
246
246
|
|
|
247
247
|
for (let i = 0; i < plen; ++i) {
|
|
248
248
|
let def;
|
|
@@ -307,21 +307,21 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isB
|
|
|
307
307
|
continue;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
def = type.getDefault(doc,
|
|
310
|
+
def = type.getDefault(doc, false);
|
|
311
311
|
if (typeof def !== 'undefined') {
|
|
312
312
|
doc_[piece] = def;
|
|
313
313
|
doc.$__.activePaths.default(p);
|
|
314
314
|
}
|
|
315
315
|
} else if (included) {
|
|
316
316
|
// selected field
|
|
317
|
-
def = type.getDefault(doc,
|
|
317
|
+
def = type.getDefault(doc, false);
|
|
318
318
|
if (typeof def !== 'undefined') {
|
|
319
319
|
doc_[piece] = def;
|
|
320
320
|
doc.$__.activePaths.default(p);
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
} else {
|
|
324
|
-
def = type.getDefault(doc,
|
|
324
|
+
def = type.getDefault(doc, false);
|
|
325
325
|
if (typeof def !== 'undefined') {
|
|
326
326
|
doc_[piece] = def;
|
|
327
327
|
doc.$__.activePaths.default(p);
|
|
@@ -595,16 +595,19 @@ Document.prototype.update = function update() {
|
|
|
595
595
|
*/
|
|
596
596
|
|
|
597
597
|
Document.prototype.updateOne = function updateOne(doc, options, callback) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
598
|
+
const query = this.constructor.updateOne({_id: this._id}, doc, options);
|
|
599
|
+
query._pre(cb => {
|
|
600
|
+
this.constructor._middleware.execPre('updateOne', this, [], cb);
|
|
601
|
+
});
|
|
602
|
+
query._post(cb => {
|
|
603
|
+
this.constructor._middleware.execPost('updateOne', this, [], {}, cb);
|
|
604
|
+
});
|
|
601
605
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
606
|
+
if (callback != null) {
|
|
607
|
+
return query.exec(callback);
|
|
608
|
+
}
|
|
605
609
|
|
|
606
|
-
|
|
607
|
-
return this.constructor.updateOne({ _id: this._id }, doc, options, callback);
|
|
610
|
+
return query;
|
|
608
611
|
};
|
|
609
612
|
|
|
610
613
|
/**
|
|
@@ -908,9 +911,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
908
911
|
} else {
|
|
909
912
|
for (i = 0; i < parts.length; ++i) {
|
|
910
913
|
const subpath = parts.slice(0, i + 1).join('.');
|
|
911
|
-
if (this.
|
|
912
|
-
// marked as dirty have precedence
|
|
913
|
-
|| this.get(subpath) === null) {
|
|
914
|
+
if (this.get(subpath) === null) {
|
|
914
915
|
pathToMark = subpath;
|
|
915
916
|
break;
|
|
916
917
|
}
|
|
@@ -1282,7 +1283,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1282
1283
|
obj = adhoc.cast(obj);
|
|
1283
1284
|
}
|
|
1284
1285
|
|
|
1285
|
-
if (schema) {
|
|
1286
|
+
if (schema != null) {
|
|
1286
1287
|
obj = schema.applyGetters(obj, this);
|
|
1287
1288
|
} else if (this.schema.nested[path] && options.virtuals) {
|
|
1288
1289
|
// Might need to apply virtuals if this is a nested path
|
|
@@ -1292,6 +1293,12 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1292
1293
|
return obj;
|
|
1293
1294
|
};
|
|
1294
1295
|
|
|
1296
|
+
/*!
|
|
1297
|
+
* ignore
|
|
1298
|
+
*/
|
|
1299
|
+
|
|
1300
|
+
Document.prototype[getSymbol] = Document.prototype.get;
|
|
1301
|
+
|
|
1295
1302
|
/**
|
|
1296
1303
|
* Returns the schematype for the given `path`.
|
|
1297
1304
|
*
|
|
@@ -1304,7 +1311,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1304
1311
|
|
|
1305
1312
|
Document.prototype.$__path = function(path) {
|
|
1306
1313
|
const adhocs = this.$__.adhocPaths;
|
|
1307
|
-
const adhocType = adhocs && adhocs[path];
|
|
1314
|
+
const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null;
|
|
1308
1315
|
|
|
1309
1316
|
if (adhocType) {
|
|
1310
1317
|
return adhocType;
|
|
@@ -2462,6 +2469,10 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
2462
2469
|
clone(options) :
|
|
2463
2470
|
{};
|
|
2464
2471
|
|
|
2472
|
+
if (!('flattenMaps' in options)) {
|
|
2473
|
+
options.flattenMaps = defaultOptions.flattenMaps;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2465
2476
|
let _minimize;
|
|
2466
2477
|
if (options.minimize != null) {
|
|
2467
2478
|
_minimize = options.minimize;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const
|
|
3
|
+
const get = require('../../helpers/get');
|
|
4
|
+
const getSymbol = require('../../helpers/symbols').getSymbol;
|
|
5
5
|
const utils = require('../../utils');
|
|
6
6
|
|
|
7
|
+
let Document;
|
|
8
|
+
|
|
7
9
|
/*!
|
|
8
10
|
* exports
|
|
9
11
|
*/
|
|
@@ -118,7 +120,7 @@ function defineKey(prop, subprops, prototype, prefix, keys, options) {
|
|
|
118
120
|
enumerable: true,
|
|
119
121
|
configurable: true,
|
|
120
122
|
get: function() {
|
|
121
|
-
return this.
|
|
123
|
+
return this[getSymbol].call(this.$__.scope || this, path);
|
|
122
124
|
},
|
|
123
125
|
set: function(v) {
|
|
124
126
|
return this.$set.call(this.$__.scope || this, path, v);
|
package/lib/helpers/get.js
CHANGED
|
@@ -7,13 +7,22 @@
|
|
|
7
7
|
|
|
8
8
|
module.exports = function get(obj, path, def) {
|
|
9
9
|
const parts = path.split('.');
|
|
10
|
+
let rest = path;
|
|
10
11
|
let cur = obj;
|
|
11
12
|
for (const part of parts) {
|
|
12
13
|
if (cur == null) {
|
|
13
14
|
return def;
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
// `lib/cast.js` depends on being able to get dotted paths in updates,
|
|
18
|
+
// like `{ $set: { 'a.b': 42 } }`
|
|
19
|
+
if (cur[rest] != null) {
|
|
20
|
+
return cur[rest];
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
cur = getProperty(cur, part);
|
|
24
|
+
|
|
25
|
+
rest = rest.substr(part.length + 1);
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
return cur == null ? def : cur;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const symbols = require('../../schema/symbols');
|
|
3
4
|
const utils = require('../../utils');
|
|
4
5
|
|
|
5
6
|
/*!
|
|
@@ -58,15 +59,26 @@ function applyHooks(model, schema, options) {
|
|
|
58
59
|
// promises and make it so that `doc.save.toString()` provides meaningful
|
|
59
60
|
// information.
|
|
60
61
|
|
|
61
|
-
const middleware = schema.s.hooks.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
const middleware = schema.s.hooks.
|
|
63
|
+
filter(hook => {
|
|
64
|
+
if (hook.name === 'updateOne') {
|
|
65
|
+
return !!hook['document'];
|
|
66
|
+
}
|
|
67
|
+
if (hook.name === 'remove') {
|
|
68
|
+
return hook['document'] == null || !!hook['document'];
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}).
|
|
72
|
+
filter(hook => {
|
|
73
|
+
// If user has overwritten the method, don't apply built-in middleware
|
|
74
|
+
if (schema.methods[hook.name]) {
|
|
75
|
+
return !hook.fn[symbols.builtInMiddleware];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return true;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
model._middleware = middleware;
|
|
70
82
|
|
|
71
83
|
objToDecorate.$__save = middleware.
|
|
72
84
|
createWrapper('save', objToDecorate.$__save, null, kareemOptions);
|
|
@@ -74,8 +86,6 @@ function applyHooks(model, schema, options) {
|
|
|
74
86
|
createWrapper('validate', objToDecorate.$__validate, null, kareemOptions);
|
|
75
87
|
objToDecorate.$__remove = middleware.
|
|
76
88
|
createWrapper('remove', objToDecorate.$__remove, null, kareemOptions);
|
|
77
|
-
objToDecorate.$__updateOne = middleware.
|
|
78
|
-
createWrapper('updateOne', objToDecorate.$__updateOne, null, kareemOptions);
|
|
79
89
|
objToDecorate.$__init = middleware.
|
|
80
90
|
createWrapperSync('init', objToDecorate.$__init, null, kareemOptions);
|
|
81
91
|
|
|
@@ -104,7 +114,7 @@ function applyHooks(model, schema, options) {
|
|
|
104
114
|
return utils.promiseOrCallback(cb, callback => {
|
|
105
115
|
this[`$__${method}`].apply(this,
|
|
106
116
|
argsWithoutCallback.concat([callback]));
|
|
107
|
-
});
|
|
117
|
+
}, model.events);
|
|
108
118
|
};
|
|
109
119
|
objToDecorate[`$__${method}`] = middleware.
|
|
110
120
|
createWrapper(method, originalMethod, null, customMethodOptions);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const defineKey = require('../document/compile').defineKey;
|
|
4
|
+
const get = require('../../helpers/get');
|
|
4
5
|
const utils = require('../../utils');
|
|
5
6
|
|
|
6
7
|
const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
|
@@ -19,9 +20,11 @@ module.exports = function discriminator(model, name, schema, tiedValue) {
|
|
|
19
20
|
throw new Error('You must pass a valid discriminator Schema');
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const applyPluginsToDiscriminators = get(model.base,
|
|
24
|
+
'options.applyPluginsToDiscriminators', false);
|
|
25
|
+
// Even if `applyPluginsToDiscriminators` isn't set, we should still apply
|
|
26
|
+
// global plugins to schemas embedded in the discriminator schema (gh-7370)
|
|
27
|
+
model.base._applyPlugins(schema, { skipTopLevel: !applyPluginsToDiscriminators });
|
|
25
28
|
|
|
26
29
|
if (model.schema.discriminatorMapping &&
|
|
27
30
|
!model.schema.discriminatorMapping.isRoot) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = function castFilterPath(query, schematype, val) {
|
|
4
|
+
const any$conditionals = Object.keys(val).some(function(k) {
|
|
5
|
+
return k.charAt(0) === '$' && k !== '$id' && k !== '$ref';
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
if (!any$conditionals) {
|
|
9
|
+
return schematype.castForQueryWrapper({
|
|
10
|
+
val: val,
|
|
11
|
+
context: query
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const ks = Object.keys(val);
|
|
16
|
+
|
|
17
|
+
let k = ks.length;
|
|
18
|
+
|
|
19
|
+
while (k--) {
|
|
20
|
+
const $cond = ks[k];
|
|
21
|
+
const nested = val[$cond];
|
|
22
|
+
|
|
23
|
+
if ($cond === '$not') {
|
|
24
|
+
if (nested && schematype && !schematype.caster) {
|
|
25
|
+
const _keys = Object.keys(nested);
|
|
26
|
+
if (_keys.length && _keys[0].charAt(0) === '$') {
|
|
27
|
+
for (const key in nested) {
|
|
28
|
+
nested[key] = schematype.castForQueryWrapper({
|
|
29
|
+
$conditional: key,
|
|
30
|
+
val: nested[key],
|
|
31
|
+
context: context
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
val[$cond] = schematype.castForQueryWrapper({
|
|
36
|
+
$conditional: $cond,
|
|
37
|
+
val: nested,
|
|
38
|
+
context: context
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context);
|
|
44
|
+
} else {
|
|
45
|
+
val[$cond] = schematype.castForQueryWrapper({
|
|
46
|
+
$conditional: $cond,
|
|
47
|
+
val: nested,
|
|
48
|
+
context: context
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return val;
|
|
54
|
+
};
|
|
@@ -9,16 +9,17 @@ module.exports = function selectPopulatedFields(query) {
|
|
|
9
9
|
|
|
10
10
|
if (opts.populate != null) {
|
|
11
11
|
const paths = Object.keys(opts.populate);
|
|
12
|
-
let i;
|
|
13
12
|
const userProvidedFields = query._userProvidedFields || {};
|
|
14
13
|
if (query.selectedInclusively()) {
|
|
15
|
-
for (i = 0; i < paths.length; ++i) {
|
|
14
|
+
for (let i = 0; i < paths.length; ++i) {
|
|
16
15
|
if (!isPathInFields(userProvidedFields, paths[i])) {
|
|
17
16
|
query.select(paths[i]);
|
|
17
|
+
} else if (userProvidedFields[paths[i]] === 0) {
|
|
18
|
+
delete query._fields[paths[i]];
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
} else if (query.selectedExclusively()) {
|
|
21
|
-
for (i = 0; i < paths.length; ++i) {
|
|
22
|
+
for (let i = 0; i < paths.length; ++i) {
|
|
22
23
|
if (userProvidedFields[paths[i]] == null) {
|
|
23
24
|
delete query._fields[paths[i]];
|
|
24
25
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* A query thunk is the function responsible for sending the query to MongoDB,
|
|
5
|
+
* like `Query#_findOne()` or `Query#_execUpdate()`. The `Query#exec()` function
|
|
6
|
+
* calls a thunk. The term "thunk" here is the traditional Node.js definition:
|
|
7
|
+
* a function that takes exactly 1 parameter, a callback.
|
|
8
|
+
*
|
|
9
|
+
* This function defines common behavior for all query thunks.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
module.exports = function wrapThunk(fn) {
|
|
13
|
+
return function _wrappedThunk(cb) {
|
|
14
|
+
++this._executionCount;
|
|
15
|
+
|
|
16
|
+
fn.call(this, cb);
|
|
17
|
+
};
|
|
18
|
+
};
|
package/lib/helpers/symbols.js
CHANGED
|
@@ -4,4 +4,8 @@ exports.validatorErrorSymbol = Symbol.for('mongoose:validatorError');
|
|
|
4
4
|
|
|
5
5
|
exports.documentArrayParent = Symbol.for('mongoose:documentArrayParent');
|
|
6
6
|
|
|
7
|
-
exports.modelSymbol = Symbol.for('mongoose#Model');
|
|
7
|
+
exports.modelSymbol = Symbol.for('mongoose#Model');
|
|
8
|
+
|
|
9
|
+
exports.getSymbol = Symbol.for('mongoose#Document#get');
|
|
10
|
+
|
|
11
|
+
exports.objectIdSymbol = Symbol.for('mongoose#ObjectId');
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const castFilterPath = require('../query/castFilterPath');
|
|
4
|
+
const modifiedPaths = require('./modifiedPaths');
|
|
5
|
+
|
|
6
|
+
module.exports = function castArrayFilters(query) {
|
|
7
|
+
const arrayFilters = query.options.arrayFilters;
|
|
8
|
+
if (!Array.isArray(arrayFilters)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const update = query.getUpdate();
|
|
13
|
+
const schema = query.schema;
|
|
14
|
+
|
|
15
|
+
const updatedPaths = modifiedPaths(update);
|
|
16
|
+
|
|
17
|
+
const updatedPathsByFilter = Object.keys(updatedPaths).reduce((cur, path) => {
|
|
18
|
+
const matches = path.match(/\$\[[^\]]+\]/g);
|
|
19
|
+
if (matches == null) {
|
|
20
|
+
return cur;
|
|
21
|
+
}
|
|
22
|
+
for (const match of matches) {
|
|
23
|
+
const firstMatch = path.indexOf(match);
|
|
24
|
+
if (firstMatch !== path.lastIndexOf(match)) {
|
|
25
|
+
throw new Error(`Path '${path}' contains the same array filter multiple times`);
|
|
26
|
+
}
|
|
27
|
+
cur[match.substring(2, match.length - 1)] = path.substr(0, firstMatch - 1);
|
|
28
|
+
}
|
|
29
|
+
return cur;
|
|
30
|
+
}, {});
|
|
31
|
+
|
|
32
|
+
for (const filter of arrayFilters) {
|
|
33
|
+
if (filter == null) {
|
|
34
|
+
throw new Error(`Got null array filter in ${arrayFilters}`);
|
|
35
|
+
}
|
|
36
|
+
const firstKey = Object.keys(filter)[0];
|
|
37
|
+
|
|
38
|
+
if (filter[firstKey] == null) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const dot = firstKey.indexOf('.');
|
|
43
|
+
let filterPath = dot === -1 ?
|
|
44
|
+
updatedPathsByFilter[firstKey] + '.0' :
|
|
45
|
+
updatedPathsByFilter[firstKey.substr(0, dot)] + '.0' + firstKey.substr(dot);
|
|
46
|
+
|
|
47
|
+
if (filterPath == null) {
|
|
48
|
+
throw new Error(`Filter path not found for ${firstKey}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// If there are multiple array filters in the path being updated, make sure
|
|
52
|
+
// to replace them so we can get the schema path.
|
|
53
|
+
filterPath = filterPath.replace(/\$\[[^\]]+\]/g, '0');
|
|
54
|
+
|
|
55
|
+
const schematype = schema.path(filterPath);
|
|
56
|
+
if (typeof filter[firstKey] === 'object') {
|
|
57
|
+
filter[firstKey] = castFilterPath(query, schematype, filter[firstKey]);
|
|
58
|
+
} else {
|
|
59
|
+
filter[firstKey] = schematype.castForQuery(filter[firstKey]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -335,20 +335,32 @@ Mongoose.prototype.pluralize = function(fn) {
|
|
|
335
335
|
/**
|
|
336
336
|
* Defines a model or retrieves it.
|
|
337
337
|
*
|
|
338
|
-
* Models defined on the `mongoose` instance are available to all connection
|
|
338
|
+
* Models defined on the `mongoose` instance are available to all connection
|
|
339
|
+
* created by the same `mongoose` instance.
|
|
340
|
+
*
|
|
341
|
+
* If you call `mongoose.model()` with twice the same name but a different schema,
|
|
342
|
+
* you will get an `OverwriteModelError`. If you call `mongoose.model()` with
|
|
343
|
+
* the same name and same schema, you'll get the same schema back.
|
|
339
344
|
*
|
|
340
345
|
* ####Example:
|
|
341
346
|
*
|
|
342
347
|
* var mongoose = require('mongoose');
|
|
343
348
|
*
|
|
344
349
|
* // define an Actor model with this mongoose instance
|
|
345
|
-
*
|
|
350
|
+
* const Schema = new Schema({ name: String });
|
|
351
|
+
* mongoose.model('Actor', schema);
|
|
346
352
|
*
|
|
347
353
|
* // create a new connection
|
|
348
354
|
* var conn = mongoose.createConnection(..);
|
|
349
355
|
*
|
|
350
|
-
* //
|
|
351
|
-
* var Actor = conn.model('Actor');
|
|
356
|
+
* // create Actor model
|
|
357
|
+
* var Actor = conn.model('Actor', schema);
|
|
358
|
+
* conn.model('Actor') === Actor; // true
|
|
359
|
+
* conn.model('Actor', schema) === Actor; // true, same schema
|
|
360
|
+
* conn.model('Actor', schema, 'actors') === Actor; // true, same schema and collection name
|
|
361
|
+
*
|
|
362
|
+
* // This throws an `OverwriteModelError` because the schema is different.
|
|
363
|
+
* conn.model('Actor', new Schema({ name: String }));
|
|
352
364
|
*
|
|
353
365
|
* _When no `collection` argument is passed, Mongoose uses the model name. If you don't like this behavior, either pass a collection name, use `mongoose.pluralize()`, or set your schemas collection name option._
|
|
354
366
|
*
|
|
@@ -366,10 +378,10 @@ Mongoose.prototype.pluralize = function(fn) {
|
|
|
366
378
|
* var M = mongoose.model('Actor', schema, collectionName)
|
|
367
379
|
*
|
|
368
380
|
* @param {String|Function} name model name or class extending Model
|
|
369
|
-
* @param {Schema} [schema]
|
|
381
|
+
* @param {Schema} [schema] the schema to use.
|
|
370
382
|
* @param {String} [collection] name (optional, inferred from model name)
|
|
371
383
|
* @param {Boolean} [skipInit] whether to skip initialization (defaults to false)
|
|
372
|
-
* @return {Model}
|
|
384
|
+
* @return {Model} The model associated with `name`. Mongoose will create the model if it doesn't already exist.
|
|
373
385
|
* @api public
|
|
374
386
|
*/
|
|
375
387
|
|
|
@@ -441,7 +453,7 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
|
|
|
441
453
|
throw new _mongoose.Error.OverwriteModelError(name);
|
|
442
454
|
}
|
|
443
455
|
|
|
444
|
-
if (collection) {
|
|
456
|
+
if (collection && collection !== _mongoose.models[name].collection.name) {
|
|
445
457
|
// subclass current model with alternate collection
|
|
446
458
|
model = _mongoose.models[name];
|
|
447
459
|
schema = model.prototype.schema;
|
|
@@ -539,16 +551,18 @@ Mongoose.prototype.modelNames = function() {
|
|
|
539
551
|
* @api private
|
|
540
552
|
*/
|
|
541
553
|
|
|
542
|
-
Mongoose.prototype._applyPlugins = function(schema) {
|
|
554
|
+
Mongoose.prototype._applyPlugins = function(schema, options) {
|
|
543
555
|
if (schema.$globalPluginsApplied) {
|
|
544
556
|
return;
|
|
545
557
|
}
|
|
546
558
|
let i;
|
|
547
559
|
let len;
|
|
548
|
-
|
|
549
|
-
|
|
560
|
+
if (!options || !options.skipTopLevel) {
|
|
561
|
+
for (i = 0, len = this.plugins.length; i < len; ++i) {
|
|
562
|
+
schema.plugin(this.plugins[i][0], this.plugins[i][1]);
|
|
563
|
+
}
|
|
564
|
+
schema.$globalPluginsApplied = true;
|
|
550
565
|
}
|
|
551
|
-
schema.$globalPluginsApplied = true;
|
|
552
566
|
for (i = 0, len = schema.childSchemas.length; i < len; ++i) {
|
|
553
567
|
this._applyPlugins(schema.childSchemas[i].schema);
|
|
554
568
|
}
|
|
@@ -572,7 +586,7 @@ Mongoose.prototype.plugin = function(fn, opts) {
|
|
|
572
586
|
};
|
|
573
587
|
|
|
574
588
|
/**
|
|
575
|
-
* The default connection
|
|
589
|
+
* The Mongoose module's default connection. Equivalent to `mongoose.connections][0]`, see [`connections`](#mongoose_Mongoose-connections).
|
|
576
590
|
*
|
|
577
591
|
* ####Example:
|
|
578
592
|
*
|
|
@@ -582,10 +596,11 @@ Mongoose.prototype.plugin = function(fn, opts) {
|
|
|
582
596
|
*
|
|
583
597
|
* This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
|
|
584
598
|
*
|
|
599
|
+
* To create a new connection, use [`createConnection()`](#mongoose_Mongoose-createConnection).
|
|
600
|
+
*
|
|
585
601
|
* @memberOf Mongoose
|
|
586
602
|
* @instance
|
|
587
|
-
* @property connection
|
|
588
|
-
* @return {Connection}
|
|
603
|
+
* @property {Connection} connection
|
|
589
604
|
* @api public
|
|
590
605
|
*/
|
|
591
606
|
|
|
@@ -600,6 +615,29 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
|
600
615
|
}
|
|
601
616
|
});
|
|
602
617
|
|
|
618
|
+
/**
|
|
619
|
+
* An array containing all [connections](connections.html) associated with this
|
|
620
|
+
* Mongoose instance. By default, there is 1 connection. Calling
|
|
621
|
+
* [`createConnection()`](#mongoose_Mongoose-createConnection) adds a connection
|
|
622
|
+
* to this array.
|
|
623
|
+
*
|
|
624
|
+
* ####Example:
|
|
625
|
+
*
|
|
626
|
+
* const mongoose = require('mongoose');
|
|
627
|
+
* mongoose.connections.length; // 1, just the default connection
|
|
628
|
+
* mongoose.connections[0] === mongoose.connection; // true
|
|
629
|
+
*
|
|
630
|
+
* mongoose.createConnection('mongodb://localhost:27017/test');
|
|
631
|
+
* mongoose.connections.length; // 2
|
|
632
|
+
*
|
|
633
|
+
* @memberOf Mongoose
|
|
634
|
+
* @instance
|
|
635
|
+
* @property {Array} connections
|
|
636
|
+
* @api public
|
|
637
|
+
*/
|
|
638
|
+
|
|
639
|
+
Mongoose.prototype.connections;
|
|
640
|
+
|
|
603
641
|
/*!
|
|
604
642
|
* Driver dependent APIs
|
|
605
643
|
*/
|