mongoose 4.12.2 → 4.12.6
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/.travis.yml +2 -0
- package/History.md +33 -1
- package/lib/collection.js +4 -1
- package/lib/connection.js +10 -4
- package/lib/drivers/node-mongodb-native/collection.js +0 -8
- package/lib/drivers/node-mongodb-native/connection.js +10 -0
- package/lib/error/browserMissingSchema.js +1 -1
- package/lib/error/cast.js +1 -1
- package/lib/error/disconnected.js +1 -1
- package/lib/error/divergentArray.js +1 -1
- package/lib/{error.js → error/index.js} +9 -9
- package/lib/error/missingSchema.js +1 -1
- package/lib/error/notFound.js +1 -1
- package/lib/error/objectExpected.js +1 -1
- package/lib/error/objectParameter.js +1 -1
- package/lib/error/overwriteModel.js +1 -1
- package/lib/error/strict.js +1 -1
- package/lib/error/validation.js +1 -1
- package/lib/error/validator.js +1 -1
- package/lib/error/version.js +1 -1
- package/lib/model.js +56 -14
- package/lib/query.js +46 -2
- package/lib/schema/documentarray.js +3 -0
- package/lib/schema/embedded.js +4 -0
- package/lib/schema/objectid.js +1 -1
- package/lib/schema/string.js +21 -3
- package/lib/schema.js +5 -3
- package/lib/schematype.js +27 -8
- package/lib/services/query/selectPopulatedFields.js +1 -1
- package/lib/services/setDefaultsOnInsert.js +4 -4
- package/lib/services/updateValidators.js +12 -8
- package/lib/types/buffer.js +12 -3
- package/package.json +3 -3
package/.travis.yml
CHANGED
package/History.md
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
|
-
4.12.
|
|
1
|
+
4.12.6 / 2017-11-01
|
|
2
|
+
===================
|
|
3
|
+
* fix(schema): make clone() copy query helpers correctly #5752
|
|
4
|
+
* fix: undeprecate `ensureIndex()` and use it by default #3280
|
|
5
|
+
|
|
6
|
+
4.12.5 / 2017-10-29
|
|
7
|
+
===================
|
|
8
|
+
* fix(query): correctly handle `$in` and required for $pull and update validators #5744
|
|
9
|
+
* feat(aggegate): add $addFields pipeline operator #5740 [AyushG3112](https://github.com/AyushG3112)
|
|
10
|
+
* fix(document): catch sync errors in document pre hooks and report as error #5738
|
|
11
|
+
* fix(populate): handle slice projections correctly when automatically selecting populated fields #5737
|
|
12
|
+
* fix(discriminator): fix hooks for embedded discriminators #5706 [wlingke](https://github.com/wlingke)
|
|
13
|
+
* fix(model): throw sane error when customer calls `mongoose.Model()` over `mongoose.model()` #2005
|
|
14
|
+
|
|
15
|
+
4.12.4 / 2017-10-21
|
|
16
|
+
===================
|
|
17
|
+
* test(plugins): add coverage for idGetter with id as a schema property #5713 [wlingke](https://github.com/wlingke)
|
|
18
|
+
* fix(model): avoid copying recursive $$context object when creating discriminator after querying #5721
|
|
19
|
+
* fix(connection): ensure connection promise helpers are removed before emitting 'connected' #5714
|
|
20
|
+
* docs(schema): add notes about runSettersOnQuery to schema setters #5705
|
|
21
|
+
* fix(collection): ensure queued operations run on the next tick #5562
|
|
22
|
+
|
|
23
|
+
4.12.3 / 2017-10-16
|
|
24
|
+
===================
|
|
25
|
+
* fix(connection): emit 'reconnect' event as well as 'reconnected' for consistency with driver #5719
|
|
26
|
+
* fix: correctly bubble up left/joined events for replica set #5718
|
|
27
|
+
* fix(connection): allow passing in `autoIndex` as top-level option rather than requiring `config.autoIndex` #5711
|
|
28
|
+
* docs(connection): improve docs regarding reconnectTries, autoReconnect, and bufferMaxEntries #5711
|
|
29
|
+
* fix(query): handle null with addToSet/push/pull/pullAll update validators #5710
|
|
30
|
+
* fix(model): handle setDefaultsOnInsert option for bulkWrite updateOne and updateMany #5708
|
|
31
|
+
* fix(query): avoid infinite recursion edge case when cloning a buffer #5702
|
|
32
|
+
|
|
33
|
+
4.12.2 / 2017-10-14
|
|
2
34
|
===================
|
|
3
35
|
* docs(faq): add FAQ about using arrow functions for getters/setters, virtuals, and methods #5700
|
|
4
36
|
* docs(schema): document the childSchemas property and add to public API #5695
|
package/lib/collection.js
CHANGED
package/lib/connection.js
CHANGED
|
@@ -763,9 +763,13 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
763
763
|
if (options) {
|
|
764
764
|
options = utils.clone(options, { retainKeyOrder: true });
|
|
765
765
|
delete options.useMongoClient;
|
|
766
|
-
|
|
767
|
-
|
|
766
|
+
var autoIndex = options.config && options.config.autoIndex != null ?
|
|
767
|
+
options.config.autoIndex :
|
|
768
|
+
options.autoIndex;
|
|
769
|
+
if (autoIndex != null) {
|
|
770
|
+
this.config.autoIndex = autoIndex !== false;
|
|
768
771
|
delete options.config;
|
|
772
|
+
delete options.autoIndex;
|
|
769
773
|
}
|
|
770
774
|
|
|
771
775
|
// Backwards compat
|
|
@@ -795,6 +799,7 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
795
799
|
// Backwards compat for mongoose 4.x
|
|
796
800
|
db.on('reconnect', function() {
|
|
797
801
|
_this.readyState = STATES.connected;
|
|
802
|
+
_this.emit('reconnect');
|
|
798
803
|
_this.emit('reconnected');
|
|
799
804
|
});
|
|
800
805
|
db.s.topology.on('reconnectFailed', function() {
|
|
@@ -808,6 +813,9 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
808
813
|
_this.emit('timeout');
|
|
809
814
|
});
|
|
810
815
|
|
|
816
|
+
delete _this.then;
|
|
817
|
+
delete _this.catch;
|
|
818
|
+
|
|
811
819
|
_this.db = db;
|
|
812
820
|
_this.readyState = STATES.connected;
|
|
813
821
|
|
|
@@ -818,8 +826,6 @@ Connection.prototype.openUri = function(uri, options, callback) {
|
|
|
818
826
|
}
|
|
819
827
|
|
|
820
828
|
callback && callback(null, _this);
|
|
821
|
-
delete _this.then;
|
|
822
|
-
delete _this.catch;
|
|
823
829
|
resolve(_this);
|
|
824
830
|
_this.emit('open');
|
|
825
831
|
});
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
var MongooseCollection = require('../../collection');
|
|
6
6
|
var Collection = require('mongodb').Collection;
|
|
7
|
-
var util = require('util');
|
|
8
7
|
var utils = require('../../utils');
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -156,13 +155,6 @@ for (var i in Collection.prototype) {
|
|
|
156
155
|
iter(i);
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
/*!
|
|
160
|
-
* ignore
|
|
161
|
-
*/
|
|
162
|
-
|
|
163
|
-
Collection.prototype.ensureIndex = util.deprecate(Collection.prototype.ensureIndex,
|
|
164
|
-
'`ensureIndex()` is deprecated in Mongoose >= 4.12.0, use `createIndex()` instead');
|
|
165
|
-
|
|
166
158
|
/**
|
|
167
159
|
* Debug print helper
|
|
168
160
|
*
|
|
@@ -162,6 +162,7 @@ function listen(conn) {
|
|
|
162
162
|
});
|
|
163
163
|
conn.db.on('reconnect', function() {
|
|
164
164
|
conn.readyState = STATES.connected;
|
|
165
|
+
conn.emit('reconnect');
|
|
165
166
|
conn.emit('reconnected');
|
|
166
167
|
conn.onOpen();
|
|
167
168
|
});
|
|
@@ -171,6 +172,7 @@ function listen(conn) {
|
|
|
171
172
|
conn.db.on('open', function(err, db) {
|
|
172
173
|
if (STATES.disconnected === conn.readyState && db && db.databaseName) {
|
|
173
174
|
conn.readyState = STATES.connected;
|
|
175
|
+
conn.emit('reconnect');
|
|
174
176
|
conn.emit('reconnected');
|
|
175
177
|
}
|
|
176
178
|
});
|
|
@@ -204,6 +206,14 @@ NativeConnection.prototype.doOpenSet = function(fn) {
|
|
|
204
206
|
: new ReplSetServers(servers, this.options.replset || this.options.replSet);
|
|
205
207
|
this.db = new Db(this.name, server, this.options.db);
|
|
206
208
|
|
|
209
|
+
this.db.s.topology.on('left', function(data) {
|
|
210
|
+
_this.emit('left', data);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
this.db.s.topology.on('joined', function(data) {
|
|
214
|
+
_this.emit('joined', data);
|
|
215
|
+
});
|
|
216
|
+
|
|
207
217
|
this.db.on('fullsetup', function() {
|
|
208
218
|
_this.emit('fullsetup');
|
|
209
219
|
});
|
package/lib/error/cast.js
CHANGED
|
@@ -37,7 +37,7 @@ module.exports = exports = MongooseError;
|
|
|
37
37
|
* @api public
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
|
-
MongooseError.messages = require('./
|
|
40
|
+
MongooseError.messages = require('./messages');
|
|
41
41
|
|
|
42
42
|
// backward compat
|
|
43
43
|
MongooseError.Messages = MongooseError.messages;
|
|
@@ -51,16 +51,16 @@ MongooseError.Messages = MongooseError.messages;
|
|
|
51
51
|
* @api public
|
|
52
52
|
*/
|
|
53
53
|
|
|
54
|
-
MongooseError.DocumentNotFoundError = require('./
|
|
54
|
+
MongooseError.DocumentNotFoundError = require('./notFound');
|
|
55
55
|
|
|
56
56
|
/*!
|
|
57
57
|
* Expose subclasses
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
|
-
MongooseError.CastError = require('./
|
|
61
|
-
MongooseError.ValidationError = require('./
|
|
62
|
-
MongooseError.ValidatorError = require('./
|
|
63
|
-
MongooseError.VersionError = require('./
|
|
64
|
-
MongooseError.OverwriteModelError = require('./
|
|
65
|
-
MongooseError.MissingSchemaError = require('./
|
|
66
|
-
MongooseError.DivergentArrayError = require('./
|
|
60
|
+
MongooseError.CastError = require('./cast');
|
|
61
|
+
MongooseError.ValidationError = require('./validation');
|
|
62
|
+
MongooseError.ValidatorError = require('./validator');
|
|
63
|
+
MongooseError.VersionError = require('./version');
|
|
64
|
+
MongooseError.OverwriteModelError = require('./overwriteModel');
|
|
65
|
+
MongooseError.MissingSchemaError = require('./missingSchema');
|
|
66
|
+
MongooseError.DivergentArrayError = require('./divergentArray');
|
package/lib/error/notFound.js
CHANGED
package/lib/error/strict.js
CHANGED
package/lib/error/validation.js
CHANGED
package/lib/error/validator.js
CHANGED
package/lib/error/version.js
CHANGED
package/lib/model.js
CHANGED
|
@@ -23,6 +23,7 @@ var isPathSelectedInclusive = require('./services/projection/isPathSelectedInclu
|
|
|
23
23
|
var mpath = require('mpath');
|
|
24
24
|
var parallel = require('async/parallel');
|
|
25
25
|
var parallelLimit = require('async/parallelLimit');
|
|
26
|
+
var setDefaultsOnInsert = require('./services/setDefaultsOnInsert');
|
|
26
27
|
var util = require('util');
|
|
27
28
|
var utils = require('./utils');
|
|
28
29
|
|
|
@@ -45,6 +46,11 @@ var VERSION_WHERE = 1,
|
|
|
45
46
|
*/
|
|
46
47
|
|
|
47
48
|
function Model(doc, fields, skipId) {
|
|
49
|
+
if (fields instanceof Schema) {
|
|
50
|
+
throw new TypeError('2nd argument to `Model` must be a POJO or string, ' +
|
|
51
|
+
'**not** a schema. Make sure you\'re calling `mongoose.model()`, not ' +
|
|
52
|
+
'`mongoose.Model()`.');
|
|
53
|
+
}
|
|
48
54
|
Document.call(this, doc, fields, skipId, true);
|
|
49
55
|
}
|
|
50
56
|
|
|
@@ -929,7 +935,7 @@ Model.init = function init(callback) {
|
|
|
929
935
|
*
|
|
930
936
|
* ####Example:
|
|
931
937
|
*
|
|
932
|
-
* Event.
|
|
938
|
+
* Event.ensureIndexes(function (err) {
|
|
933
939
|
* if (err) return handleError(err);
|
|
934
940
|
* });
|
|
935
941
|
*
|
|
@@ -952,14 +958,14 @@ Model.init = function init(callback) {
|
|
|
952
958
|
* @api public
|
|
953
959
|
*/
|
|
954
960
|
|
|
955
|
-
Model.
|
|
961
|
+
Model.ensureIndexes = function ensureIndexes(options, callback) {
|
|
956
962
|
if (typeof options === 'function') {
|
|
957
963
|
callback = options;
|
|
958
964
|
options = null;
|
|
959
965
|
}
|
|
960
966
|
|
|
961
967
|
if (options && options.__noPromise) {
|
|
962
|
-
|
|
968
|
+
_ensureIndexes(this, options, callback);
|
|
963
969
|
return;
|
|
964
970
|
}
|
|
965
971
|
|
|
@@ -970,7 +976,7 @@ Model.createIndexes = Model.ensureIndexes = function createIndexes(options, call
|
|
|
970
976
|
var _this = this;
|
|
971
977
|
var Promise = PromiseProvider.get();
|
|
972
978
|
return new Promise.ES6(function(resolve, reject) {
|
|
973
|
-
|
|
979
|
+
_ensureIndexes(_this, options || {}, function(error) {
|
|
974
980
|
if (error) {
|
|
975
981
|
callback && callback(error);
|
|
976
982
|
reject(error);
|
|
@@ -981,8 +987,31 @@ Model.createIndexes = Model.ensureIndexes = function createIndexes(options, call
|
|
|
981
987
|
});
|
|
982
988
|
};
|
|
983
989
|
|
|
984
|
-
|
|
990
|
+
/**
|
|
991
|
+
* Similar to `ensureIndexes()`, except for it uses the [`createIndex`](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#createIndex)
|
|
992
|
+
* function. The `ensureIndex()` function checks to see if an index with that
|
|
993
|
+
* name already exists, and, if not, does not attempt to create the index.
|
|
994
|
+
* `createIndex()` bypasses this check.
|
|
995
|
+
*
|
|
996
|
+
* @param {Object} [options] internal options
|
|
997
|
+
* @param {Function} [cb] optional callback
|
|
998
|
+
* @return {Promise}
|
|
999
|
+
* @api public
|
|
1000
|
+
*/
|
|
1001
|
+
|
|
1002
|
+
Model.createIndexes = function createIndexes(options, callback) {
|
|
1003
|
+
if (typeof options === 'function') {
|
|
1004
|
+
callback = options;
|
|
1005
|
+
options = {};
|
|
1006
|
+
}
|
|
1007
|
+
options = options || {};
|
|
1008
|
+
options.createIndex = true;
|
|
1009
|
+
return this.ensureIndexes(options, callback);
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
function _ensureIndexes(model, options, callback) {
|
|
985
1013
|
var indexes = model.schema.indexes();
|
|
1014
|
+
options = options || {};
|
|
986
1015
|
|
|
987
1016
|
var done = function(err) {
|
|
988
1017
|
if (err && model.schema.options.emitIndexErrors) {
|
|
@@ -1009,7 +1038,7 @@ function _createIndexes(model, options, callback) {
|
|
|
1009
1038
|
};
|
|
1010
1039
|
|
|
1011
1040
|
var create = function() {
|
|
1012
|
-
if (options
|
|
1041
|
+
if (options._automatic) {
|
|
1013
1042
|
if (model.schema.options.autoIndex === false ||
|
|
1014
1043
|
(model.schema.options.autoIndex == null && model.db.config.autoIndex === false)) {
|
|
1015
1044
|
return done();
|
|
@@ -1024,7 +1053,8 @@ function _createIndexes(model, options, callback) {
|
|
|
1024
1053
|
_handleSafe(options);
|
|
1025
1054
|
|
|
1026
1055
|
indexSingleStart(indexFields, options);
|
|
1027
|
-
|
|
1056
|
+
var methodName = options.createIndex ? 'createIndex' : 'ensureIndex';
|
|
1057
|
+
model.collection[methodName](indexFields, indexOptions, utils.tick(function(err, name) {
|
|
1028
1058
|
indexSingleDone(err, indexFields, indexOptions, name);
|
|
1029
1059
|
if (err) {
|
|
1030
1060
|
return done(err);
|
|
@@ -2239,12 +2269,18 @@ Model.bulkWrite = function(ops, options, callback) {
|
|
|
2239
2269
|
});
|
|
2240
2270
|
};
|
|
2241
2271
|
} else if (op['updateOne']) {
|
|
2272
|
+
op = op['updateOne'];
|
|
2242
2273
|
return function(callback) {
|
|
2243
2274
|
try {
|
|
2244
|
-
op['
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2275
|
+
op['filter'] = cast(_this.schema, op['filter']);
|
|
2276
|
+
op['update'] = castUpdate(_this.schema, op['update'],
|
|
2277
|
+
_this.schema.options.strict);
|
|
2278
|
+
if (op.setDefaultsOnInsert) {
|
|
2279
|
+
setDefaultsOnInsert(op['filter'], _this.schema, op['update'], {
|
|
2280
|
+
setDefaultsOnInsert: true,
|
|
2281
|
+
upsert: op.upsert
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2248
2284
|
} catch (error) {
|
|
2249
2285
|
return callback(error);
|
|
2250
2286
|
}
|
|
@@ -2252,14 +2288,20 @@ Model.bulkWrite = function(ops, options, callback) {
|
|
|
2252
2288
|
callback(null);
|
|
2253
2289
|
};
|
|
2254
2290
|
} else if (op['updateMany']) {
|
|
2291
|
+
op = op['updateMany'];
|
|
2255
2292
|
return function(callback) {
|
|
2256
2293
|
try {
|
|
2257
|
-
op['
|
|
2258
|
-
|
|
2259
|
-
op['updateMany']['update'] = castUpdate(_this.schema, op['updateMany']['update'], {
|
|
2294
|
+
op['filter'] = cast(_this.schema, op['filter']);
|
|
2295
|
+
op['update'] = castUpdate(_this.schema, op['update'], {
|
|
2260
2296
|
strict: _this.schema.options.strict,
|
|
2261
2297
|
overwrite: false
|
|
2262
2298
|
});
|
|
2299
|
+
if (op.setDefaultsOnInsert) {
|
|
2300
|
+
setDefaultsOnInsert(op['filter'], _this.schema, op['update'], {
|
|
2301
|
+
setDefaultsOnInsert: true,
|
|
2302
|
+
upsert: op.upsert
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2263
2305
|
} catch (error) {
|
|
2264
2306
|
return callback(error);
|
|
2265
2307
|
}
|
package/lib/query.js
CHANGED
|
@@ -15,6 +15,7 @@ var mquery = require('mquery');
|
|
|
15
15
|
var readPref = require('./drivers').ReadPreference;
|
|
16
16
|
var selectPopulatedFields = require('./services/query/selectPopulatedFields');
|
|
17
17
|
var setDefaultsOnInsert = require('./services/setDefaultsOnInsert');
|
|
18
|
+
var slice = require('sliced');
|
|
18
19
|
var updateValidators = require('./services/updateValidators');
|
|
19
20
|
var util = require('util');
|
|
20
21
|
var utils = require('./utils');
|
|
@@ -263,6 +264,49 @@ Query.prototype.toConstructor = function toConstructor() {
|
|
|
263
264
|
* @api public
|
|
264
265
|
*/
|
|
265
266
|
|
|
267
|
+
Query.prototype.slice = function() {
|
|
268
|
+
if (arguments.length === 0) {
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
this._validate('slice');
|
|
273
|
+
|
|
274
|
+
var path;
|
|
275
|
+
var val;
|
|
276
|
+
|
|
277
|
+
if (arguments.length === 1) {
|
|
278
|
+
var arg = arguments[0];
|
|
279
|
+
if (typeof arg === 'object' && !Array.isArray(arg)) {
|
|
280
|
+
var keys = Object.keys(arg);
|
|
281
|
+
var numKeys = keys.length;
|
|
282
|
+
for (var i = 0; i < numKeys; ++i) {
|
|
283
|
+
this.slice(keys[i], arg[keys[i]]);
|
|
284
|
+
}
|
|
285
|
+
return this;
|
|
286
|
+
}
|
|
287
|
+
this._ensurePath('slice');
|
|
288
|
+
path = this._path;
|
|
289
|
+
val = arguments[0];
|
|
290
|
+
} else if (arguments.length === 2) {
|
|
291
|
+
if ('number' === typeof arguments[0]) {
|
|
292
|
+
this._ensurePath('slice');
|
|
293
|
+
path = this._path;
|
|
294
|
+
val = slice(arguments);
|
|
295
|
+
} else {
|
|
296
|
+
path = arguments[0];
|
|
297
|
+
val = arguments[1];
|
|
298
|
+
}
|
|
299
|
+
} else if (arguments.length === 3) {
|
|
300
|
+
path = arguments[0];
|
|
301
|
+
val = slice(arguments, 1);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
var p = {};
|
|
305
|
+
p[path] = { $slice: val };
|
|
306
|
+
return this.select(p);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
|
|
266
310
|
/**
|
|
267
311
|
* Specifies the complementary comparison value for paths specified with `where()`
|
|
268
312
|
*
|
|
@@ -2227,7 +2271,7 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
2227
2271
|
};
|
|
2228
2272
|
} else {
|
|
2229
2273
|
castedDoc = castDoc(this, opts.overwrite);
|
|
2230
|
-
castedDoc = setDefaultsOnInsert(this, schema, castedDoc, opts);
|
|
2274
|
+
castedDoc = setDefaultsOnInsert(this._conditions, schema, castedDoc, opts);
|
|
2231
2275
|
if (!castedDoc) {
|
|
2232
2276
|
if (opts.upsert) {
|
|
2233
2277
|
// still need to do the upsert to empty doc
|
|
@@ -2939,7 +2983,7 @@ function _update(query, op, conditions, doc, options, callback) {
|
|
|
2939
2983
|
}
|
|
2940
2984
|
}
|
|
2941
2985
|
|
|
2942
|
-
castedDoc = setDefaultsOnInsert(query, query.schema, castedDoc, options);
|
|
2986
|
+
castedDoc = setDefaultsOnInsert(query._conditions, query.schema, castedDoc, options);
|
|
2943
2987
|
if (!castedDoc) {
|
|
2944
2988
|
// Make sure promises know that this is still an update, see gh-2796
|
|
2945
2989
|
query.op = op;
|
|
@@ -11,6 +11,7 @@ var EventEmitter = require('events').EventEmitter;
|
|
|
11
11
|
var MongooseDocumentArray = require('../types/documentarray');
|
|
12
12
|
var SchemaType = require('../schematype');
|
|
13
13
|
var Subdocument = require('../types/embedded');
|
|
14
|
+
var applyHooks = require('../services/model/applyHooks');
|
|
14
15
|
var discriminator = require('../services/model/discriminator');
|
|
15
16
|
var util = require('util');
|
|
16
17
|
var utils = require('../utils');
|
|
@@ -119,6 +120,8 @@ DocumentArray.prototype.discriminator = function(name, schema) {
|
|
|
119
120
|
|
|
120
121
|
this.casterConstructor.discriminators[name] = EmbeddedDocument;
|
|
121
122
|
|
|
123
|
+
applyHooks(EmbeddedDocument, schema);
|
|
124
|
+
|
|
122
125
|
return this.casterConstructor.discriminators[name];
|
|
123
126
|
};
|
|
124
127
|
|
package/lib/schema/embedded.js
CHANGED
|
@@ -8,6 +8,7 @@ var $exists = require('./operators/exists');
|
|
|
8
8
|
var EventEmitter = require('events').EventEmitter;
|
|
9
9
|
var SchemaType = require('../schematype');
|
|
10
10
|
var Subdocument = require('../types/subdocument');
|
|
11
|
+
var applyHooks = require('../services/model/applyHooks');
|
|
11
12
|
var castToNumber = require('./operators/helpers').castToNumber;
|
|
12
13
|
var discriminator = require('../services/model/discriminator');
|
|
13
14
|
var geospatial = require('./operators/geospatial');
|
|
@@ -253,5 +254,8 @@ Embedded.prototype.discriminator = function(name, schema) {
|
|
|
253
254
|
discriminator(this.caster, name, schema);
|
|
254
255
|
|
|
255
256
|
this.caster.discriminators[name] = _createConstructor(schema);
|
|
257
|
+
|
|
258
|
+
applyHooks(this.caster.discriminators[name], schema);
|
|
259
|
+
|
|
256
260
|
return this.caster.discriminators[name];
|
|
257
261
|
};
|
package/lib/schema/objectid.js
CHANGED
|
@@ -20,7 +20,7 @@ var SchemaType = require('../schematype'),
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
function ObjectId(key, options) {
|
|
23
|
-
var isKeyHexStr = typeof key === 'string' && /^a-f0-9$/i.test(key);
|
|
23
|
+
var isKeyHexStr = typeof key === 'string' && key.length === 24 && /^a-f0-9$/i.test(key);
|
|
24
24
|
var suppressWarning = options && options.suppressWarning;
|
|
25
25
|
if ((isKeyHexStr || typeof key === 'undefined') && !suppressWarning) {
|
|
26
26
|
console.warn('mongoose: To create a new ObjectId please try ' +
|
package/lib/schema/string.js
CHANGED
|
@@ -116,7 +116,7 @@ SchemaString.prototype.enum = function() {
|
|
|
116
116
|
};
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
|
-
* Adds a lowercase setter.
|
|
119
|
+
* Adds a lowercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
|
|
120
120
|
*
|
|
121
121
|
* ####Example:
|
|
122
122
|
*
|
|
@@ -125,6 +125,12 @@ SchemaString.prototype.enum = function() {
|
|
|
125
125
|
* var m = new M({ email: 'SomeEmail@example.COM' });
|
|
126
126
|
* console.log(m.email) // someemail@example.com
|
|
127
127
|
*
|
|
128
|
+
* NOTE: Setters do not run on queries by default. Use the `runSettersOnQuery` option:
|
|
129
|
+
*
|
|
130
|
+
* // Must use `runSettersOnQuery` as shown below, otherwise `email` will
|
|
131
|
+
* // **not** be lowercased.
|
|
132
|
+
* M.updateOne({}, { $set: { email: 'SomeEmail@example.COM' } }, { runSettersOnQuery: true });
|
|
133
|
+
*
|
|
128
134
|
* @api public
|
|
129
135
|
* @return {SchemaType} this
|
|
130
136
|
*/
|
|
@@ -145,7 +151,7 @@ SchemaString.prototype.lowercase = function(shouldApply) {
|
|
|
145
151
|
};
|
|
146
152
|
|
|
147
153
|
/**
|
|
148
|
-
* Adds an uppercase setter.
|
|
154
|
+
* Adds an uppercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
|
|
149
155
|
*
|
|
150
156
|
* ####Example:
|
|
151
157
|
*
|
|
@@ -154,6 +160,12 @@ SchemaString.prototype.lowercase = function(shouldApply) {
|
|
|
154
160
|
* var m = new M({ caps: 'an example' });
|
|
155
161
|
* console.log(m.caps) // AN EXAMPLE
|
|
156
162
|
*
|
|
163
|
+
* NOTE: Setters do not run on queries by default. Use the `runSettersOnQuery` option:
|
|
164
|
+
*
|
|
165
|
+
* // Must use `runSettersOnQuery` as shown below, otherwise `email` will
|
|
166
|
+
* // **not** be lowercased.
|
|
167
|
+
* M.updateOne({}, { $set: { email: 'SomeEmail@example.COM' } }, { runSettersOnQuery: true });
|
|
168
|
+
*
|
|
157
169
|
* @api public
|
|
158
170
|
* @return {SchemaType} this
|
|
159
171
|
*/
|
|
@@ -174,7 +186,7 @@ SchemaString.prototype.uppercase = function(shouldApply) {
|
|
|
174
186
|
};
|
|
175
187
|
|
|
176
188
|
/**
|
|
177
|
-
* Adds a trim setter.
|
|
189
|
+
* Adds a trim [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
|
|
178
190
|
*
|
|
179
191
|
* The string value will be trimmed when set.
|
|
180
192
|
*
|
|
@@ -187,6 +199,12 @@ SchemaString.prototype.uppercase = function(shouldApply) {
|
|
|
187
199
|
* var m = new M({ name: string })
|
|
188
200
|
* console.log(m.name.length) // 9
|
|
189
201
|
*
|
|
202
|
+
* NOTE: Setters do not run on queries by default. Use the `runSettersOnQuery` option:
|
|
203
|
+
*
|
|
204
|
+
* // Must use `runSettersOnQuery` as shown below, otherwise `email` will
|
|
205
|
+
* // **not** be lowercased.
|
|
206
|
+
* M.updateOne({}, { $set: { email: 'SomeEmail@example.COM' } }, { runSettersOnQuery: true });
|
|
207
|
+
*
|
|
190
208
|
* @api public
|
|
191
209
|
* @return {SchemaType} this
|
|
192
210
|
*/
|
package/lib/schema.js
CHANGED
|
@@ -298,11 +298,13 @@ Schema.prototype.tree;
|
|
|
298
298
|
Schema.prototype.clone = function() {
|
|
299
299
|
var s = new Schema(this.paths, this.options);
|
|
300
300
|
// Clone the call queue
|
|
301
|
+
var cloneOpts = { retainKeyOrder: true };
|
|
301
302
|
s.callQueue = this.callQueue.map(function(f) { return f; });
|
|
302
|
-
s.methods = utils.clone(this.methods);
|
|
303
|
-
s.statics = utils.clone(this.statics);
|
|
303
|
+
s.methods = utils.clone(this.methods, cloneOpts);
|
|
304
|
+
s.statics = utils.clone(this.statics, cloneOpts);
|
|
305
|
+
s.query = utils.clone(this.query, cloneOpts);
|
|
304
306
|
s.plugins = Array.prototype.slice.call(this.plugins);
|
|
305
|
-
s._indexes = utils.clone(this._indexes);
|
|
307
|
+
s._indexes = utils.clone(this._indexes, cloneOpts);
|
|
306
308
|
s.s.hooks = this.s.hooks.clone();
|
|
307
309
|
return s;
|
|
308
310
|
};
|
package/lib/schematype.js
CHANGED
|
@@ -42,6 +42,13 @@ function SchemaType(path, options, instance) {
|
|
|
42
42
|
this[i].apply(this, opts);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
Object.defineProperty(this, '$$context', {
|
|
47
|
+
enumerable: false,
|
|
48
|
+
configurable: false,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: null
|
|
51
|
+
});
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
/**
|
|
@@ -237,25 +244,37 @@ SchemaType.prototype.sparse = function(bool) {
|
|
|
237
244
|
*
|
|
238
245
|
* You can set up email lower case normalization easily via a Mongoose setter.
|
|
239
246
|
*
|
|
240
|
-
* function toLower
|
|
247
|
+
* function toLower(v) {
|
|
241
248
|
* return v.toLowerCase();
|
|
242
249
|
* }
|
|
243
250
|
*
|
|
244
251
|
* var UserSchema = new Schema({
|
|
245
252
|
* email: { type: String, set: toLower }
|
|
246
|
-
* })
|
|
253
|
+
* });
|
|
247
254
|
*
|
|
248
|
-
* var User = db.model('User', UserSchema)
|
|
255
|
+
* var User = db.model('User', UserSchema);
|
|
249
256
|
*
|
|
250
|
-
* var user = new User({email: 'AVENUE@Q.COM'})
|
|
257
|
+
* var user = new User({email: 'AVENUE@Q.COM'});
|
|
251
258
|
* console.log(user.email); // 'avenue@q.com'
|
|
252
259
|
*
|
|
253
260
|
* // or
|
|
254
|
-
* var user = new User
|
|
255
|
-
* user.email = 'Avenue@Q.com'
|
|
256
|
-
* console.log(user.email) // 'avenue@q.com'
|
|
261
|
+
* var user = new User();
|
|
262
|
+
* user.email = 'Avenue@Q.com';
|
|
263
|
+
* console.log(user.email); // 'avenue@q.com'
|
|
257
264
|
*
|
|
258
|
-
* As you can see above, setters allow you to transform the data before it
|
|
265
|
+
* As you can see above, setters allow you to transform the data before it stored in MongoDB.
|
|
266
|
+
*
|
|
267
|
+
* NOTE: setters by default do **not** run on queries by default.
|
|
268
|
+
*
|
|
269
|
+
* // Will **not** run the `toLower()` setter by default.
|
|
270
|
+
* User.updateOne({ _id: _id }, { $set: { email: 'AVENUE@Q.COM' } });
|
|
271
|
+
*
|
|
272
|
+
* Use the `runSettersOnQuery` option to opt-in to running setters on `User.update()`:
|
|
273
|
+
*
|
|
274
|
+
* // Turn on `runSettersOnQuery` to run the setters from your schema.
|
|
275
|
+
* User.updateOne({ _id: _id }, { $set: { email: 'AVENUE@Q.COM' } }, {
|
|
276
|
+
* runSettersOnQuery: true
|
|
277
|
+
* });
|
|
259
278
|
*
|
|
260
279
|
* _NOTE: we could have also just used the built-in `lowercase: true` SchemaType option instead of defining our own function._
|
|
261
280
|
*
|
|
@@ -5,7 +5,7 @@ var modifiedPaths = require('./common').modifiedPaths;
|
|
|
5
5
|
/**
|
|
6
6
|
* Applies defaults to update and findOneAndUpdate operations.
|
|
7
7
|
*
|
|
8
|
-
* @param {
|
|
8
|
+
* @param {Object} filter
|
|
9
9
|
* @param {Schema} schema
|
|
10
10
|
* @param {Object} castedDoc
|
|
11
11
|
* @param {Object} options
|
|
@@ -13,7 +13,7 @@ var modifiedPaths = require('./common').modifiedPaths;
|
|
|
13
13
|
* @api private
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
module.exports = function(
|
|
16
|
+
module.exports = function(filter, schema, castedDoc, options) {
|
|
17
17
|
var keys = Object.keys(castedDoc || {});
|
|
18
18
|
var updatedKeys = {};
|
|
19
19
|
var updatedValues = {};
|
|
@@ -33,11 +33,11 @@ module.exports = function(query, schema, castedDoc, options) {
|
|
|
33
33
|
modifiedPaths(castedDoc, '', modified);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
var paths = Object.keys(
|
|
36
|
+
var paths = Object.keys(filter);
|
|
37
37
|
var numPaths = paths.length;
|
|
38
38
|
for (i = 0; i < numPaths; ++i) {
|
|
39
39
|
var path = paths[i];
|
|
40
|
-
var condition =
|
|
40
|
+
var condition = filter[path];
|
|
41
41
|
if (condition && typeof condition === 'object') {
|
|
42
42
|
var conditionKeys = Object.keys(condition);
|
|
43
43
|
var numConditionKeys = conditionKeys.length;
|
|
@@ -29,19 +29,22 @@ module.exports = function(query, schema, castedDoc, options) {
|
|
|
29
29
|
var numKeys = keys.length;
|
|
30
30
|
var hasDollarUpdate = false;
|
|
31
31
|
var modified = {};
|
|
32
|
+
var currentUpdate;
|
|
33
|
+
var key;
|
|
32
34
|
|
|
33
35
|
for (var i = 0; i < numKeys; ++i) {
|
|
34
36
|
if (keys[i].charAt(0) === '$') {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
hasDollarUpdate = true;
|
|
38
|
+
if (keys[i] === '$push' || keys[i] === '$addToSet') {
|
|
37
39
|
_keys = Object.keys(castedDoc[keys[i]]);
|
|
38
40
|
for (var ii = 0; ii < _keys.length; ++ii) {
|
|
39
|
-
|
|
41
|
+
currentUpdate = castedDoc[keys[i]][_keys[ii]];
|
|
42
|
+
if (currentUpdate && currentUpdate.$each) {
|
|
40
43
|
arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []).
|
|
41
|
-
concat(
|
|
44
|
+
concat(currentUpdate.$each);
|
|
42
45
|
} else {
|
|
43
46
|
arrayAtomicUpdates[_keys[ii]] = (arrayAtomicUpdates[_keys[ii]] || []).
|
|
44
|
-
concat([
|
|
47
|
+
concat([currentUpdate]);
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
continue;
|
|
@@ -53,14 +56,15 @@ module.exports = function(query, schema, castedDoc, options) {
|
|
|
53
56
|
for (var j = 0; j < numPaths; ++j) {
|
|
54
57
|
var updatedPath = paths[j].replace('.$.', '.0.');
|
|
55
58
|
updatedPath = updatedPath.replace(/\.\$$/, '.0');
|
|
56
|
-
|
|
59
|
+
key = keys[i];
|
|
60
|
+
if (key === '$set' || key === '$setOnInsert' ||
|
|
61
|
+
key === '$pull' || key === '$pullAll') {
|
|
57
62
|
updatedValues[updatedPath] = flat[paths[j]];
|
|
58
|
-
} else if (
|
|
63
|
+
} else if (key === '$unset') {
|
|
59
64
|
updatedValues[updatedPath] = undefined;
|
|
60
65
|
}
|
|
61
66
|
updatedKeys[updatedPath] = true;
|
|
62
67
|
}
|
|
63
|
-
hasDollarUpdate = true;
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
|
package/lib/types/buffer.js
CHANGED
|
@@ -46,9 +46,18 @@ function MongooseBuffer(value, encode, offset) {
|
|
|
46
46
|
|
|
47
47
|
// make sure these internal props don't show up in Object.keys()
|
|
48
48
|
Object.defineProperties(buf, {
|
|
49
|
-
validators: {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
validators: {
|
|
50
|
+
value: [],
|
|
51
|
+
enumerable: false
|
|
52
|
+
},
|
|
53
|
+
_path: {
|
|
54
|
+
value: path,
|
|
55
|
+
enumerable: false
|
|
56
|
+
},
|
|
57
|
+
_parent: {
|
|
58
|
+
value: doc,
|
|
59
|
+
enumerable: false
|
|
60
|
+
}
|
|
52
61
|
});
|
|
53
62
|
|
|
54
63
|
if (doc && typeof path === 'string') {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "4.12.
|
|
4
|
+
"version": "4.12.6",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"async": "2.1.4",
|
|
23
23
|
"bson": "~1.0.4",
|
|
24
|
-
"hooks-fixed": "2.0.
|
|
24
|
+
"hooks-fixed": "2.0.2",
|
|
25
25
|
"kareem": "1.5.0",
|
|
26
26
|
"mongodb": "2.2.33",
|
|
27
27
|
"mpath": "0.3.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"node-static": "0.7.7",
|
|
53
53
|
"nsp": "~2.8.1",
|
|
54
54
|
"power-assert": "1.4.1",
|
|
55
|
-
"q": "1.
|
|
55
|
+
"q": "1.5.1",
|
|
56
56
|
"tbd": "0.6.4",
|
|
57
57
|
"uglify-js": "2.7.0",
|
|
58
58
|
"uuid": "2.0.3",
|