mongoose 5.4.3 → 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 +7 -0
- package/lib/cast.js +1 -1
- package/lib/helpers/query/castFilterPath.js +54 -0
- package/lib/helpers/update/castArrayFilters.js +62 -0
- package/lib/index.js +27 -3
- package/lib/model.js +25 -13
- package/lib/plugins/sharding.js +4 -0
- package/lib/query.js +17 -0
- package/lib/schema.js +4 -0
- package/package.json +1 -1
package/History.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
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
|
+
|
|
1
8
|
5.4.3 / 2019-01-09
|
|
2
9
|
==================
|
|
3
10
|
* fix(populate): handle `count` option when using `Document#populate()` on a virtual #7380
|
package/lib/cast.js
CHANGED
|
@@ -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
|
+
};
|
|
@@ -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
|
@@ -586,7 +586,7 @@ Mongoose.prototype.plugin = function(fn, opts) {
|
|
|
586
586
|
};
|
|
587
587
|
|
|
588
588
|
/**
|
|
589
|
-
* The default connection
|
|
589
|
+
* The Mongoose module's default connection. Equivalent to `mongoose.connections][0]`, see [`connections`](#mongoose_Mongoose-connections).
|
|
590
590
|
*
|
|
591
591
|
* ####Example:
|
|
592
592
|
*
|
|
@@ -596,10 +596,11 @@ Mongoose.prototype.plugin = function(fn, opts) {
|
|
|
596
596
|
*
|
|
597
597
|
* This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
|
|
598
598
|
*
|
|
599
|
+
* To create a new connection, use [`createConnection()`](#mongoose_Mongoose-createConnection).
|
|
600
|
+
*
|
|
599
601
|
* @memberOf Mongoose
|
|
600
602
|
* @instance
|
|
601
|
-
* @property connection
|
|
602
|
-
* @return {Connection}
|
|
603
|
+
* @property {Connection} connection
|
|
603
604
|
* @api public
|
|
604
605
|
*/
|
|
605
606
|
|
|
@@ -614,6 +615,29 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
|
614
615
|
}
|
|
615
616
|
});
|
|
616
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
|
+
|
|
617
641
|
/*!
|
|
618
642
|
* Driver dependent APIs
|
|
619
643
|
*/
|
package/lib/model.js
CHANGED
|
@@ -171,13 +171,12 @@ Model.prototype.baseModelName;
|
|
|
171
171
|
* MyModel.events.on('error', err => console.log(err.message));
|
|
172
172
|
*
|
|
173
173
|
* // Prints a 'CastError' because of the above handler
|
|
174
|
-
* await MyModel.findOne({ _id: 'notanid' }).catch(
|
|
174
|
+
* await MyModel.findOne({ _id: 'notanid' }).catch(noop);
|
|
175
175
|
*
|
|
176
176
|
* @api public
|
|
177
177
|
* @fires error whenever any query or model function errors
|
|
178
|
-
* @property events
|
|
179
178
|
* @memberOf Model
|
|
180
|
-
* @static
|
|
179
|
+
* @static events
|
|
181
180
|
*/
|
|
182
181
|
|
|
183
182
|
Model.events;
|
|
@@ -193,15 +192,28 @@ Model.events;
|
|
|
193
192
|
|
|
194
193
|
Model._middleware;
|
|
195
194
|
|
|
195
|
+
/*!
|
|
196
|
+
* ignore
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
function _applyCustomWhere(doc, where) {
|
|
200
|
+
if (doc.$where == null) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const keys = Object.keys(doc.$where);
|
|
205
|
+
const len = keys.length;
|
|
206
|
+
for (let i = 0; i < len; ++i) {
|
|
207
|
+
where[keys[i]] = doc.$where[keys[i]];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
196
211
|
/*!
|
|
197
212
|
* ignore
|
|
198
213
|
*/
|
|
199
214
|
|
|
200
215
|
Model.prototype.$__handleSave = function(options, callback) {
|
|
201
216
|
const _this = this;
|
|
202
|
-
let i;
|
|
203
|
-
let keys;
|
|
204
|
-
let len;
|
|
205
217
|
let saveOptions = {};
|
|
206
218
|
|
|
207
219
|
if ('safe' in options) {
|
|
@@ -285,13 +297,7 @@ Model.prototype.$__handleSave = function(options, callback) {
|
|
|
285
297
|
return;
|
|
286
298
|
}
|
|
287
299
|
|
|
288
|
-
|
|
289
|
-
keys = Object.keys(this.$where);
|
|
290
|
-
len = keys.length;
|
|
291
|
-
for (i = 0; i < len; ++i) {
|
|
292
|
-
where[keys[i]] = this.$where[keys[i]];
|
|
293
|
-
}
|
|
294
|
-
}
|
|
300
|
+
_applyCustomWhere(this, where);
|
|
295
301
|
|
|
296
302
|
this[modelCollectionSymbol].updateOne(where, delta[1], saveOptions, function(err, ret) {
|
|
297
303
|
if (err) {
|
|
@@ -420,6 +426,7 @@ function generateVersionError(doc, modifiedPaths) {
|
|
|
420
426
|
* @param {Boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://docs.mongodb.com/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
|
|
421
427
|
* @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern).
|
|
422
428
|
* @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names)
|
|
429
|
+
* @param {Boolean} [options.timestamps=true] if `false` and [timestamps](./guide.html#timestamps) are enabled, skip timestamps for this `save()`.
|
|
423
430
|
* @param {Function} [fn] optional callback
|
|
424
431
|
* @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
|
|
425
432
|
* @api public
|
|
@@ -458,8 +465,11 @@ Model.prototype.save = function(options, fn) {
|
|
|
458
465
|
return cb(parallelSave);
|
|
459
466
|
}
|
|
460
467
|
|
|
468
|
+
this.$__.saveOptions = options;
|
|
469
|
+
|
|
461
470
|
this.$__save(options, error => {
|
|
462
471
|
this.$__.saving = undefined;
|
|
472
|
+
delete this.$__.saveOptions;
|
|
463
473
|
|
|
464
474
|
if (error) {
|
|
465
475
|
this.$__handleReject(error);
|
|
@@ -915,6 +925,8 @@ Model.prototype.$__remove = function $__remove(options, cb) {
|
|
|
915
925
|
return cb(where);
|
|
916
926
|
}
|
|
917
927
|
|
|
928
|
+
_applyCustomWhere(this, where);
|
|
929
|
+
|
|
918
930
|
this[modelCollectionSymbol].deleteOne(where, options, err => {
|
|
919
931
|
if (!err) {
|
|
920
932
|
this.$__.isDeleted = true;
|
package/lib/plugins/sharding.js
CHANGED
package/lib/query.js
CHANGED
|
@@ -11,6 +11,7 @@ const QueryCursor = require('./cursor/QueryCursor');
|
|
|
11
11
|
const ReadPreference = require('./driver').get().ReadPreference;
|
|
12
12
|
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
|
|
13
13
|
const cast = require('./cast');
|
|
14
|
+
const castArrayFilters = require('./helpers/update/castArrayFilters');
|
|
14
15
|
const castUpdate = require('./helpers/query/castUpdate');
|
|
15
16
|
const completeMany = require('./helpers/query/completeMany');
|
|
16
17
|
const get = require('./helpers/get');
|
|
@@ -1728,6 +1729,18 @@ Query.prototype._castConditions = function() {
|
|
|
1728
1729
|
}
|
|
1729
1730
|
};
|
|
1730
1731
|
|
|
1732
|
+
/*!
|
|
1733
|
+
* ignore
|
|
1734
|
+
*/
|
|
1735
|
+
|
|
1736
|
+
function _castArrayFilters(query) {
|
|
1737
|
+
try {
|
|
1738
|
+
castArrayFilters(query);
|
|
1739
|
+
} catch (err) {
|
|
1740
|
+
query.error(err);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1731
1744
|
/**
|
|
1732
1745
|
* Thunk around find()
|
|
1733
1746
|
*
|
|
@@ -3147,6 +3160,8 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
3147
3160
|
return callback(castedQuery);
|
|
3148
3161
|
}
|
|
3149
3162
|
|
|
3163
|
+
_castArrayFilters(this);
|
|
3164
|
+
|
|
3150
3165
|
const opts = this._optionsForExec(model);
|
|
3151
3166
|
|
|
3152
3167
|
if ('strict' in opts) {
|
|
@@ -3385,6 +3400,8 @@ function _updateThunk(op, callback) {
|
|
|
3385
3400
|
|
|
3386
3401
|
this._castConditions();
|
|
3387
3402
|
|
|
3403
|
+
_castArrayFilters(this);
|
|
3404
|
+
|
|
3388
3405
|
if (this.error() != null) {
|
|
3389
3406
|
callback(this.error());
|
|
3390
3407
|
return null;
|
package/lib/schema.js
CHANGED
|
@@ -918,6 +918,10 @@ Schema.prototype.setupTimestamp = function(timestamps) {
|
|
|
918
918
|
this.add(schemaAdditions);
|
|
919
919
|
|
|
920
920
|
this.pre('save', function(next) {
|
|
921
|
+
if (get(this, '$__.saveOptions.timestamps') === false) {
|
|
922
|
+
return next();
|
|
923
|
+
}
|
|
924
|
+
|
|
921
925
|
const defaultTimestamp = (this.ownerDocument ? this.ownerDocument() : this).
|
|
922
926
|
constructor.base.now();
|
|
923
927
|
const auto_id = this._id && this._id.auto;
|