mongoose 5.0.6 → 5.0.10
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/README.md +20 -18
- package/browser.js +6 -0
- package/lib/aggregate.js +72 -0
- package/lib/cast.js +34 -6
- package/lib/collection.js +16 -0
- package/lib/connection.js +8 -2
- package/lib/cursor/AggregationCursor.js +12 -40
- package/lib/cursor/QueryCursor.js +1 -1
- package/lib/document.js +84 -18
- package/lib/drivers/node-mongodb-native/connection.js +10 -1
- package/lib/index.js +2 -1
- package/lib/model.js +5 -3
- package/lib/query.js +84 -20
- package/lib/queryhelpers.js +36 -5
- package/lib/schema/array.js +17 -6
- package/lib/schema/documentarray.js +13 -10
- package/lib/schema/embedded.js +36 -7
- package/lib/schema/objectid.js +2 -0
- package/lib/schema.js +30 -25
- package/lib/schematype.js +29 -6
- package/lib/services/model/discriminator.js +10 -5
- package/lib/services/query/castUpdate.js +28 -8
- package/lib/types/documentarray.js +25 -8
- package/lib/utils.js +1 -1
- package/migrating_to_5.md +47 -2
- package/package.json +6 -6
- package/lib/document_provider.web.js +0 -17
- package/mongoose5_transparent.png +0 -0
package/lib/index.js
CHANGED
|
@@ -79,6 +79,7 @@ Mongoose.prototype.STATES = STATES;
|
|
|
79
79
|
* Currently supported options are:
|
|
80
80
|
* - 'debug': prints the operations mongoose sends to MongoDB to the console
|
|
81
81
|
* - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
|
|
82
|
+
* - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
|
|
82
83
|
*
|
|
83
84
|
* @param {String} key
|
|
84
85
|
* @param {String|Function|Boolean} value
|
|
@@ -476,7 +477,7 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
|
|
|
476
477
|
});
|
|
477
478
|
|
|
478
479
|
/*!
|
|
479
|
-
* Driver
|
|
480
|
+
* Driver dependent APIs
|
|
480
481
|
*/
|
|
481
482
|
|
|
482
483
|
var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
|
package/lib/model.js
CHANGED
|
@@ -22,6 +22,7 @@ var applyStatics = require('./services/model/applyStatics');
|
|
|
22
22
|
var cast = require('./cast');
|
|
23
23
|
var castUpdate = require('./services/query/castUpdate');
|
|
24
24
|
var discriminator = require('./services/model/discriminator');
|
|
25
|
+
var getDiscriminatorByValue = require('./queryhelpers').getDiscriminatorByValue;
|
|
25
26
|
var internalToObjectOptions = require('./options').internalToObjectOptions;
|
|
26
27
|
var isPathSelectedInclusive = require('./services/projection/isPathSelectedInclusive');
|
|
27
28
|
var get = require('lodash.get');
|
|
@@ -829,10 +830,11 @@ Model.prototype.model = function model(name) {
|
|
|
829
830
|
*
|
|
830
831
|
* @param {String} name discriminator model name
|
|
831
832
|
* @param {Schema} schema discriminator model schema
|
|
833
|
+
* @param {String} value discriminator model typeKey value
|
|
832
834
|
* @api public
|
|
833
835
|
*/
|
|
834
836
|
|
|
835
|
-
Model.discriminator = function(name, schema) {
|
|
837
|
+
Model.discriminator = function(name, schema, value) {
|
|
836
838
|
var model;
|
|
837
839
|
if (typeof name === 'function') {
|
|
838
840
|
model = name;
|
|
@@ -842,7 +844,7 @@ Model.discriminator = function(name, schema) {
|
|
|
842
844
|
}
|
|
843
845
|
}
|
|
844
846
|
|
|
845
|
-
schema = discriminator(this, name, schema);
|
|
847
|
+
schema = discriminator(this, name, schema, value);
|
|
846
848
|
if (this.db.models[name]) {
|
|
847
849
|
throw new OverwriteModelError(name);
|
|
848
850
|
}
|
|
@@ -2034,7 +2036,7 @@ Model.create = function create(doc, callback) {
|
|
|
2034
2036
|
args.forEach(doc => {
|
|
2035
2037
|
toExecute.push(callback => {
|
|
2036
2038
|
var Model = this.discriminators && doc[discriminatorKey] ?
|
|
2037
|
-
this.discriminators[doc[discriminatorKey]] :
|
|
2039
|
+
this.discriminators[doc[discriminatorKey]] || getDiscriminatorByValue(this, doc[discriminatorKey]) :
|
|
2038
2040
|
this;
|
|
2039
2041
|
var toSave = doc;
|
|
2040
2042
|
var callbackWrapper = (error, doc) => {
|
package/lib/query.js
CHANGED
|
@@ -1021,6 +1021,15 @@ Query.prototype.setOptions = function(options, overwrite) {
|
|
|
1021
1021
|
}
|
|
1022
1022
|
}
|
|
1023
1023
|
|
|
1024
|
+
if ('useFindAndModify' in options) {
|
|
1025
|
+
this._mongooseOptions.useFindAndModify = options.useFindAndModify;
|
|
1026
|
+
delete options.useFindAndModify;
|
|
1027
|
+
}
|
|
1028
|
+
if ('omitUndefined' in options) {
|
|
1029
|
+
this._mongooseOptions.omitUndefined = options.omitUndefined;
|
|
1030
|
+
delete options.omitUndefined;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1024
1033
|
return Query.base.setOptions.call(this, options);
|
|
1025
1034
|
};
|
|
1026
1035
|
|
|
@@ -1437,14 +1446,14 @@ function completeMany(model, docs, fields, userProvidedFields, pop, callback) {
|
|
|
1437
1446
|
var opts = pop ? { populated: pop } : undefined;
|
|
1438
1447
|
var error = null;
|
|
1439
1448
|
function init(_error) {
|
|
1449
|
+
if (_error != null) {
|
|
1450
|
+
error = error || _error;
|
|
1451
|
+
}
|
|
1440
1452
|
if (error != null) {
|
|
1453
|
+
--count || callback(error);
|
|
1441
1454
|
return;
|
|
1442
1455
|
}
|
|
1443
|
-
|
|
1444
|
-
error = _error;
|
|
1445
|
-
return callback(error);
|
|
1446
|
-
}
|
|
1447
|
-
--count || callback(null, arr);
|
|
1456
|
+
--count || callback(error, arr);
|
|
1448
1457
|
}
|
|
1449
1458
|
for (var i = 0; i < len; ++i) {
|
|
1450
1459
|
arr[i] = helpers.createModel(model, docs[i], fields, userProvidedFields);
|
|
@@ -1590,13 +1599,6 @@ Query.prototype.findOne = function(conditions, projection, options, callback) {
|
|
|
1590
1599
|
this.merge(conditions);
|
|
1591
1600
|
|
|
1592
1601
|
prepareDiscriminatorCriteria(this);
|
|
1593
|
-
|
|
1594
|
-
try {
|
|
1595
|
-
this.cast(this.model);
|
|
1596
|
-
this.error(null);
|
|
1597
|
-
} catch (err) {
|
|
1598
|
-
this.error(err);
|
|
1599
|
-
}
|
|
1600
1602
|
} else if (conditions != null) {
|
|
1601
1603
|
this.error(new ObjectParameterError(conditions, 'filter', 'findOne'));
|
|
1602
1604
|
}
|
|
@@ -2143,8 +2145,6 @@ Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
|
|
|
2143
2145
|
*/
|
|
2144
2146
|
|
|
2145
2147
|
Query.prototype._findOneAndUpdate = function(callback) {
|
|
2146
|
-
this._castConditions();
|
|
2147
|
-
|
|
2148
2148
|
if (this.error() != null) {
|
|
2149
2149
|
return callback(this.error());
|
|
2150
2150
|
}
|
|
@@ -2238,8 +2238,6 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
|
|
|
2238
2238
|
* @api private
|
|
2239
2239
|
*/
|
|
2240
2240
|
Query.prototype._findOneAndRemove = function(callback) {
|
|
2241
|
-
this._castConditions();
|
|
2242
|
-
|
|
2243
2241
|
if (this.error() != null) {
|
|
2244
2242
|
return callback(this.error());
|
|
2245
2243
|
}
|
|
@@ -2377,8 +2375,68 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
2377
2375
|
});
|
|
2378
2376
|
};
|
|
2379
2377
|
|
|
2378
|
+
var _callback;
|
|
2379
|
+
|
|
2380
|
+
var useFindAndModify = true;
|
|
2381
|
+
var base = _this.model && _this.model.base;
|
|
2382
|
+
if ('useFindAndModify' in base.options) {
|
|
2383
|
+
useFindAndModify = base.get('useFindAndModify');
|
|
2384
|
+
}
|
|
2385
|
+
if ('useFindAndModify' in options) {
|
|
2386
|
+
useFindAndModify = options.useFindAndModify;
|
|
2387
|
+
}
|
|
2388
|
+
if (useFindAndModify === false) {
|
|
2389
|
+
// Bypass mquery
|
|
2390
|
+
var collection = _this._collection.collection;
|
|
2391
|
+
if ('new' in opts) {
|
|
2392
|
+
opts.returnOriginal = !opts['new'];
|
|
2393
|
+
delete opts['new'];
|
|
2394
|
+
}
|
|
2395
|
+
if ('fields' in opts) {
|
|
2396
|
+
opts.projection = opts.fields;
|
|
2397
|
+
delete opts.fields;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
if (type === 'remove') {
|
|
2401
|
+
collection.findOneAndDelete(castedQuery, opts, utils.tick(function(error, res) {
|
|
2402
|
+
return cb(error, res ? res.value : res, res);
|
|
2403
|
+
}));
|
|
2404
|
+
|
|
2405
|
+
return this;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
if (opts.runValidators && doValidate) {
|
|
2409
|
+
_callback = function(error) {
|
|
2410
|
+
if (error) {
|
|
2411
|
+
return callback(error);
|
|
2412
|
+
}
|
|
2413
|
+
if (castedDoc && castedDoc.toBSON) {
|
|
2414
|
+
castedDoc = castedDoc.toBSON();
|
|
2415
|
+
}
|
|
2416
|
+
collection.findOneAndUpdate(castedQuery, castedDoc, opts, utils.tick(function(error, res) {
|
|
2417
|
+
return cb(error, res ? res.value : res, res);
|
|
2418
|
+
}));
|
|
2419
|
+
};
|
|
2420
|
+
|
|
2421
|
+
try {
|
|
2422
|
+
doValidate(_callback);
|
|
2423
|
+
} catch (error) {
|
|
2424
|
+
callback(error);
|
|
2425
|
+
}
|
|
2426
|
+
} else {
|
|
2427
|
+
if (castedDoc && castedDoc.toBSON) {
|
|
2428
|
+
castedDoc = castedDoc.toBSON();
|
|
2429
|
+
}
|
|
2430
|
+
collection.findOneAndUpdate(castedQuery, castedDoc, opts, utils.tick(function(error, res) {
|
|
2431
|
+
return cb(error, res ? res.value : res, res);
|
|
2432
|
+
}));
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
return this;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2380
2438
|
if (opts.runValidators && doValidate) {
|
|
2381
|
-
|
|
2439
|
+
_callback = function(error) {
|
|
2382
2440
|
if (error) {
|
|
2383
2441
|
return callback(error);
|
|
2384
2442
|
}
|
|
@@ -3006,9 +3064,16 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
|
|
|
3006
3064
|
} else {
|
|
3007
3065
|
strict = true;
|
|
3008
3066
|
}
|
|
3067
|
+
|
|
3068
|
+
var omitUndefined = false;
|
|
3069
|
+
if ('omitUndefined' in this._mongooseOptions) {
|
|
3070
|
+
omitUndefined = this._mongooseOptions.omitUndefined;
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3009
3073
|
return castUpdate(this.schema, obj, {
|
|
3010
3074
|
overwrite: overwrite,
|
|
3011
|
-
strict: strict
|
|
3075
|
+
strict: strict,
|
|
3076
|
+
omitUndefined
|
|
3012
3077
|
}, this);
|
|
3013
3078
|
};
|
|
3014
3079
|
|
|
@@ -3214,8 +3279,7 @@ Query.prototype._applyPaths = function applyPaths() {
|
|
|
3214
3279
|
|
|
3215
3280
|
/**
|
|
3216
3281
|
* Returns a wrapper around a [mongodb driver cursor](http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html).
|
|
3217
|
-
* A QueryCursor exposes a
|
|
3218
|
-
* interface, as well as a `.next()` function.
|
|
3282
|
+
* A QueryCursor exposes a Streams3 interface, as well as a `.next()` function.
|
|
3219
3283
|
*
|
|
3220
3284
|
* The `.cursor()` function triggers pre find hooks, but **not** post find hooks.
|
|
3221
3285
|
*
|
package/lib/queryhelpers.js
CHANGED
|
@@ -46,6 +46,34 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
|
|
|
46
46
|
return pop;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
+
|
|
50
|
+
/*!
|
|
51
|
+
* returns discriminator by discriminatorMapping.value
|
|
52
|
+
*
|
|
53
|
+
* @param {Model} model
|
|
54
|
+
* @param {string} value
|
|
55
|
+
*/
|
|
56
|
+
function getDiscriminatorByValue(model, value) {
|
|
57
|
+
var discriminator = null;
|
|
58
|
+
if (!model.discriminators) {
|
|
59
|
+
return discriminator;
|
|
60
|
+
}
|
|
61
|
+
for (var name in model.discriminators) {
|
|
62
|
+
var it = model.discriminators[name];
|
|
63
|
+
if (
|
|
64
|
+
it.schema &&
|
|
65
|
+
it.schema.discriminatorMapping &&
|
|
66
|
+
it.schema.discriminatorMapping.value == value
|
|
67
|
+
) {
|
|
68
|
+
discriminator = it;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return discriminator;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
exports.getDiscriminatorByValue = getDiscriminatorByValue;
|
|
76
|
+
|
|
49
77
|
/*!
|
|
50
78
|
* If the document is a mapped discriminator type, it returns a model instance for that type, otherwise,
|
|
51
79
|
* it returns an instance of the given model.
|
|
@@ -65,11 +93,14 @@ exports.createModel = function createModel(model, doc, fields, userProvidedField
|
|
|
65
93
|
? discriminatorMapping.key
|
|
66
94
|
: null;
|
|
67
95
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
var
|
|
71
|
-
|
|
72
|
-
|
|
96
|
+
var value = doc[key];
|
|
97
|
+
if (key && value && model.discriminators) {
|
|
98
|
+
var discriminator = model.discriminators[value] || getDiscriminatorByValue(model, value);
|
|
99
|
+
if (discriminator) {
|
|
100
|
+
var _fields = utils.clone(userProvidedFields);
|
|
101
|
+
exports.applyPaths(_fields, discriminator.schema);
|
|
102
|
+
return new discriminator(undefined, _fields, true);
|
|
103
|
+
}
|
|
73
104
|
}
|
|
74
105
|
|
|
75
106
|
return new model(undefined, fields, true);
|
package/lib/schema/array.js
CHANGED
|
@@ -22,6 +22,7 @@ var util = require('util');
|
|
|
22
22
|
var utils = require('../utils');
|
|
23
23
|
var castToNumber = require('./operators/helpers').castToNumber;
|
|
24
24
|
var geospatial = require('./operators/geospatial');
|
|
25
|
+
var getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
|
|
25
26
|
|
|
26
27
|
var MongooseArray;
|
|
27
28
|
var EmbeddedDoc;
|
|
@@ -93,7 +94,7 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
|
|
96
|
-
|
|
97
|
+
var defaultFn = function() {
|
|
97
98
|
var arr = [];
|
|
98
99
|
if (fn) {
|
|
99
100
|
arr = defaultArr();
|
|
@@ -102,7 +103,9 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
|
|
102
103
|
}
|
|
103
104
|
// Leave it up to `cast()` to convert the array
|
|
104
105
|
return arr;
|
|
105
|
-
}
|
|
106
|
+
};
|
|
107
|
+
defaultFn.$runBeforeSetters = true;
|
|
108
|
+
this.default(defaultFn);
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
|
|
@@ -247,10 +250,18 @@ SchemaArray.prototype.castForQuery = function($conditional, value) {
|
|
|
247
250
|
|
|
248
251
|
if (val &&
|
|
249
252
|
Constructor.discriminators &&
|
|
250
|
-
Constructor.schema
|
|
251
|
-
|
|
252
|
-
Constructor.
|
|
253
|
-
|
|
253
|
+
Constructor.schema &&
|
|
254
|
+
Constructor.schema.options &&
|
|
255
|
+
Constructor.schema.options.discriminatorKey) {
|
|
256
|
+
if (typeof val[Constructor.schema.options.discriminatorKey] === 'string' &&
|
|
257
|
+
Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]]) {
|
|
258
|
+
Constructor = Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]];
|
|
259
|
+
} else {
|
|
260
|
+
var constructorByValue = getDiscriminatorByValue(Constructor, val[Constructor.schema.options.discriminatorKey]);
|
|
261
|
+
if (constructorByValue) {
|
|
262
|
+
Constructor = constructorByValue;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
254
265
|
}
|
|
255
266
|
|
|
256
267
|
var proto = this.casterConstructor.prototype;
|
|
@@ -12,6 +12,7 @@ var SchemaType = require('../schematype');
|
|
|
12
12
|
var discriminator = require('../services/model/discriminator');
|
|
13
13
|
var util = require('util');
|
|
14
14
|
var utils = require('../utils');
|
|
15
|
+
var getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
|
|
15
16
|
|
|
16
17
|
var MongooseDocumentArray;
|
|
17
18
|
var Subdocument;
|
|
@@ -181,13 +182,7 @@ DocumentArray.prototype.doValidate = function(array, fn, scope, options) {
|
|
|
181
182
|
undefined, i);
|
|
182
183
|
}
|
|
183
184
|
|
|
184
|
-
|
|
185
|
-
// complain
|
|
186
|
-
if (doc.$__original_validate) {
|
|
187
|
-
doc.$__original_validate({__noPromise: true}, callback);
|
|
188
|
-
} else {
|
|
189
|
-
doc.validate({__noPromise: true}, callback);
|
|
190
|
-
}
|
|
185
|
+
doc.$__validate(callback);
|
|
191
186
|
}
|
|
192
187
|
}, scope);
|
|
193
188
|
};
|
|
@@ -297,9 +292,17 @@ DocumentArray.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
297
292
|
|
|
298
293
|
var Constructor = this.casterConstructor;
|
|
299
294
|
if (Constructor.discriminators &&
|
|
300
|
-
|
|
301
|
-
Constructor.
|
|
302
|
-
|
|
295
|
+
Constructor.schema &&
|
|
296
|
+
Constructor.schema.options &&
|
|
297
|
+
typeof value[i][Constructor.schema.options.discriminatorKey] === 'string') {
|
|
298
|
+
if (Constructor.discriminators[value[i][Constructor.schema.options.discriminatorKey]]) {
|
|
299
|
+
Constructor = Constructor.discriminators[value[i][Constructor.schema.options.discriminatorKey]];
|
|
300
|
+
} else {
|
|
301
|
+
var constructorByValue = getDiscriminatorByValue(Constructor, value[i][Constructor.schema.options.discriminatorKey]);
|
|
302
|
+
if (constructorByValue) {
|
|
303
|
+
Constructor = constructorByValue;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
303
306
|
}
|
|
304
307
|
|
|
305
308
|
// Check if the document has a different schema (re gh-3701)
|
package/lib/schema/embedded.js
CHANGED
|
@@ -11,6 +11,7 @@ const castToNumber = require('./operators/helpers').castToNumber;
|
|
|
11
11
|
const discriminator = require('../services/model/discriminator');
|
|
12
12
|
const geospatial = require('./operators/geospatial');
|
|
13
13
|
const internalToObjectOptions = require('../options').internalToObjectOptions;
|
|
14
|
+
var getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
|
|
14
15
|
|
|
15
16
|
let Subdocument;
|
|
16
17
|
|
|
@@ -140,9 +141,15 @@ Embedded.prototype.cast = function(val, doc, init, priorVal) {
|
|
|
140
141
|
var discriminatorKey = Constructor.schema.options.discriminatorKey;
|
|
141
142
|
if (val != null &&
|
|
142
143
|
Constructor.discriminators &&
|
|
143
|
-
typeof val[discriminatorKey] === 'string'
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
typeof val[discriminatorKey] === 'string') {
|
|
145
|
+
if (Constructor.discriminators[val[discriminatorKey]]) {
|
|
146
|
+
Constructor = Constructor.discriminators[val[discriminatorKey]];
|
|
147
|
+
} else {
|
|
148
|
+
var constructorByValue = getDiscriminatorByValue(Constructor, val[discriminatorKey]);
|
|
149
|
+
if (constructorByValue) {
|
|
150
|
+
Constructor = constructorByValue;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
146
153
|
}
|
|
147
154
|
|
|
148
155
|
var subdoc;
|
|
@@ -188,7 +195,22 @@ Embedded.prototype.castForQuery = function($conditional, val) {
|
|
|
188
195
|
val = this._applySetters(val);
|
|
189
196
|
}
|
|
190
197
|
|
|
191
|
-
|
|
198
|
+
var Constructor = this.caster;
|
|
199
|
+
var discriminatorKey = Constructor.schema.options.discriminatorKey;
|
|
200
|
+
if (val != null &&
|
|
201
|
+
Constructor.discriminators &&
|
|
202
|
+
typeof val[discriminatorKey] === 'string') {
|
|
203
|
+
if (Constructor.discriminators[val[discriminatorKey]]) {
|
|
204
|
+
Constructor = Constructor.discriminators[val[discriminatorKey]];
|
|
205
|
+
} else {
|
|
206
|
+
var constructorByValue = getDiscriminatorByValue(Constructor, val[discriminatorKey]);
|
|
207
|
+
if (constructorByValue) {
|
|
208
|
+
Constructor = constructorByValue;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return new Constructor(val);
|
|
192
214
|
};
|
|
193
215
|
|
|
194
216
|
/**
|
|
@@ -202,11 +224,18 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
202
224
|
var discriminatorKey = Constructor.schema.options.discriminatorKey;
|
|
203
225
|
if (value != null &&
|
|
204
226
|
Constructor.discriminators &&
|
|
205
|
-
typeof value[discriminatorKey] === 'string'
|
|
206
|
-
|
|
207
|
-
|
|
227
|
+
typeof value[discriminatorKey] === 'string') {
|
|
228
|
+
if (Constructor.discriminators[value[discriminatorKey]]) {
|
|
229
|
+
Constructor = Constructor.discriminators[value[discriminatorKey]];
|
|
230
|
+
} else {
|
|
231
|
+
var constructorByValue = getDiscriminatorByValue(Constructor, value[discriminatorKey]);
|
|
232
|
+
if (constructorByValue) {
|
|
233
|
+
Constructor = constructorByValue;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
208
236
|
}
|
|
209
237
|
|
|
238
|
+
|
|
210
239
|
SchemaType.prototype.doValidate.call(this, value, function(error) {
|
|
211
240
|
if (error) {
|
|
212
241
|
return fn(error);
|
package/lib/schema/objectid.js
CHANGED
package/lib/schema.js
CHANGED
|
@@ -29,7 +29,6 @@ var mpath = require('mpath');
|
|
|
29
29
|
* - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
|
|
30
30
|
* - [capped](/docs/guide.html#capped): bool - defaults to false
|
|
31
31
|
* - [collection](/docs/guide.html#collection): string - no default
|
|
32
|
-
* - [emitIndexErrors](/docs/guide.html#emitIndexErrors): bool - defaults to false.
|
|
33
32
|
* - [id](/docs/guide.html#id): bool - defaults to true
|
|
34
33
|
* - [_id](/docs/guide.html#_id): bool - defaults to true
|
|
35
34
|
* - `minimize`: bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true
|
|
@@ -1333,33 +1332,39 @@ Schema.prototype.indexes = function() {
|
|
|
1333
1332
|
if (path.options.excludeIndexes !== true) {
|
|
1334
1333
|
collectIndexes(path.schema, prefix + key + '.');
|
|
1335
1334
|
}
|
|
1336
|
-
} else {
|
|
1337
|
-
index = path._index || (path.caster && path.caster._index);
|
|
1338
|
-
|
|
1339
|
-
if (index !== false && index !== null && index !== undefined) {
|
|
1340
|
-
field = {};
|
|
1341
|
-
isObject = utils.isObject(index);
|
|
1342
|
-
options = isObject ? index : {};
|
|
1343
|
-
type = typeof index === 'string' ? index :
|
|
1344
|
-
isObject ? index.type :
|
|
1345
|
-
false;
|
|
1346
|
-
|
|
1347
|
-
if (type && ~Schema.indexTypes.indexOf(type)) {
|
|
1348
|
-
field[prefix + key] = type;
|
|
1349
|
-
} else if (options.text) {
|
|
1350
|
-
field[prefix + key] = 'text';
|
|
1351
|
-
delete options.text;
|
|
1352
|
-
} else {
|
|
1353
|
-
field[prefix + key] = 1;
|
|
1354
|
-
}
|
|
1355
1335
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1336
|
+
// Retained to minimize risk of backwards breaking changes due to
|
|
1337
|
+
// gh-6113
|
|
1338
|
+
if ((path instanceof MongooseTypes.DocumentArray)) {
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1360
1342
|
|
|
1361
|
-
|
|
1343
|
+
index = path._index || (path.caster && path.caster._index);
|
|
1344
|
+
|
|
1345
|
+
if (index !== false && index !== null && index !== undefined) {
|
|
1346
|
+
field = {};
|
|
1347
|
+
isObject = utils.isObject(index);
|
|
1348
|
+
options = isObject ? index : {};
|
|
1349
|
+
type = typeof index === 'string' ? index :
|
|
1350
|
+
isObject ? index.type :
|
|
1351
|
+
false;
|
|
1352
|
+
|
|
1353
|
+
if (type && ~Schema.indexTypes.indexOf(type)) {
|
|
1354
|
+
field[prefix + key] = type;
|
|
1355
|
+
} else if (options.text) {
|
|
1356
|
+
field[prefix + key] = 'text';
|
|
1357
|
+
delete options.text;
|
|
1358
|
+
} else {
|
|
1359
|
+
field[prefix + key] = 1;
|
|
1362
1360
|
}
|
|
1361
|
+
|
|
1362
|
+
delete options.type;
|
|
1363
|
+
if (!('background' in options)) {
|
|
1364
|
+
options.background = true;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
indexes.push([field, options]);
|
|
1363
1368
|
}
|
|
1364
1369
|
}
|
|
1365
1370
|
|
package/lib/schematype.js
CHANGED
|
@@ -245,15 +245,19 @@ SchemaType.prototype.sparse = function(bool) {
|
|
|
245
245
|
* }
|
|
246
246
|
*
|
|
247
247
|
* // defining within the schema
|
|
248
|
-
* var s = new Schema({ name: { type: String, set: capitalize }})
|
|
248
|
+
* var s = new Schema({ name: { type: String, set: capitalize }});
|
|
249
249
|
*
|
|
250
|
-
* // or
|
|
250
|
+
* // or with the SchemaType
|
|
251
251
|
* var s = new Schema({ name: String })
|
|
252
|
-
* s.path('name').set(capitalize)
|
|
252
|
+
* s.path('name').set(capitalize);
|
|
253
253
|
*
|
|
254
|
-
* Setters allow you to transform the data before it gets to the raw mongodb
|
|
254
|
+
* Setters allow you to transform the data before it gets to the raw mongodb
|
|
255
|
+
* document or query.
|
|
255
256
|
*
|
|
256
|
-
* Suppose you are implementing user registration for a website. Users provide
|
|
257
|
+
* Suppose you are implementing user registration for a website. Users provide
|
|
258
|
+
* an email and password, which gets saved to mongodb. The email is a string
|
|
259
|
+
* that you will want to normalize to lower case, in order to avoid one email
|
|
260
|
+
* having more than one account -- e.g., otherwise, avenue@q.com can be registered for 2 accounts via avenue@q.com and AvEnUe@Q.CoM.
|
|
257
261
|
*
|
|
258
262
|
* You can set up email lower case normalization easily via a Mongoose setter.
|
|
259
263
|
*
|
|
@@ -276,7 +280,8 @@ SchemaType.prototype.sparse = function(bool) {
|
|
|
276
280
|
* console.log(user.email); // 'avenue@q.com'
|
|
277
281
|
* User.updateOne({ _id: _id }, { $set: { email: 'AVENUE@Q.COM' } }); // update to 'avenue@q.com'
|
|
278
282
|
*
|
|
279
|
-
* As you can see above, setters allow you to transform the data before it
|
|
283
|
+
* As you can see above, setters allow you to transform the data before it
|
|
284
|
+
* stored in MongoDB, or before executing a query.
|
|
280
285
|
*
|
|
281
286
|
* _NOTE: we could have also just used the built-in `lowercase: true` SchemaType option instead of defining our own function._
|
|
282
287
|
*
|
|
@@ -303,6 +308,24 @@ SchemaType.prototype.sparse = function(bool) {
|
|
|
303
308
|
* console.log(v.name); // name is required
|
|
304
309
|
* console.log(v.taxonomy); // Parvovirinae
|
|
305
310
|
*
|
|
311
|
+
* You can also use setters to modify other properties on the document. If
|
|
312
|
+
* you're setting a property `name` on a document, the setter will run with
|
|
313
|
+
* `this` as the document. Be careful, in mongoose 5 setters will also run
|
|
314
|
+
* when querying by `name` with `this` as the query.
|
|
315
|
+
*
|
|
316
|
+
* ```javascript
|
|
317
|
+
* const nameSchema = new Schema({ name: String, keywords: [String] });
|
|
318
|
+
* nameSchema.path('name').set(function(v) {
|
|
319
|
+
* // Need to check if `this` is a document, because in mongoose 5
|
|
320
|
+
* // setters will also run on queries, in which case `this` will be a
|
|
321
|
+
* // mongoose query object.
|
|
322
|
+
* if (this instanceof Document && v != null) {
|
|
323
|
+
* this.keywords = v.split(' ');
|
|
324
|
+
* }
|
|
325
|
+
* return v;
|
|
326
|
+
* });
|
|
327
|
+
* ```
|
|
328
|
+
*
|
|
306
329
|
* @param {Function} fn
|
|
307
330
|
* @return {SchemaType} this
|
|
308
331
|
* @api public
|
|
@@ -14,7 +14,7 @@ var CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
|
|
14
14
|
* ignore
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
module.exports = function discriminator(model, name, schema) {
|
|
17
|
+
module.exports = function discriminator(model, name, schema, tiedValue) {
|
|
18
18
|
if (!(schema && schema.instanceOfSchema)) {
|
|
19
19
|
throw new Error('You must pass a valid discriminator Schema');
|
|
20
20
|
}
|
|
@@ -46,6 +46,11 @@ module.exports = function discriminator(model, name, schema) {
|
|
|
46
46
|
'" cannot have field with name "' + key + '"');
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
var value = name;
|
|
50
|
+
if (typeof tiedValue == 'string' && tiedValue.length) {
|
|
51
|
+
value = tiedValue;
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
function merge(schema, baseSchema) {
|
|
50
55
|
if (baseSchema.paths._id &&
|
|
51
56
|
baseSchema.paths._id.options &&
|
|
@@ -59,11 +64,11 @@ module.exports = function discriminator(model, name, schema) {
|
|
|
59
64
|
|
|
60
65
|
var obj = {};
|
|
61
66
|
obj[key] = {
|
|
62
|
-
default:
|
|
67
|
+
default: value,
|
|
63
68
|
select: true,
|
|
64
69
|
set: function(newName) {
|
|
65
|
-
if (newName ===
|
|
66
|
-
return
|
|
70
|
+
if (newName === value) {
|
|
71
|
+
return value;
|
|
67
72
|
}
|
|
68
73
|
throw new Error('Can\'t set discriminator key "' + key + '"');
|
|
69
74
|
},
|
|
@@ -71,7 +76,7 @@ module.exports = function discriminator(model, name, schema) {
|
|
|
71
76
|
};
|
|
72
77
|
obj[key][schema.options.typeKey] = String;
|
|
73
78
|
schema.add(obj);
|
|
74
|
-
schema.discriminatorMapping = {key: key, value:
|
|
79
|
+
schema.discriminatorMapping = {key: key, value: value, isRoot: false};
|
|
75
80
|
|
|
76
81
|
if (baseSchema.options.collection) {
|
|
77
82
|
schema.options.collection = baseSchema.options.collection;
|