mongoose 5.0.9 → 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 +12 -0
- package/lib/cast.js +34 -6
- package/lib/document.js +25 -2
- package/lib/index.js +1 -1
- package/lib/query.js +0 -4
- package/lib/schema/array.js +4 -2
- package/lib/schema/embedded.js +16 -2
- package/lib/schema/objectid.js +2 -0
- package/lib/schematype.js +29 -6
- package/migrating_to_5.md +15 -0
- package/package.json +1 -1
package/History.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
5.0.10 / 2018-03-12
|
|
2
|
+
===================
|
|
3
|
+
* docs(schematype): add notes re: running setters on queries #6209
|
|
4
|
+
* docs: fix typo #6208 [kamagatos](https://github.com/kamagatos)
|
|
5
|
+
* fix(query): only call setters once on query filter props for findOneAndUpdate and findOneAndRemove #6203
|
|
6
|
+
* docs: elaborate on connection string changes in migration guide #6193
|
|
7
|
+
* fix(document): skip applyDefaults if subdoc is null #6187
|
|
8
|
+
* docs: fix schematypes docs and link to them #6176
|
|
9
|
+
* docs(faq): add FAQs re: array defaults and casting aggregation pipelines #6184 #6176 #6170 [lineus](https://github.com/lineus)
|
|
10
|
+
* fix(document): ensure primitive defaults are set and built-in default functions run before setters #6155
|
|
11
|
+
* fix(query): handle single embedded embedded discriminators in castForQuery #6027
|
|
12
|
+
|
|
1
13
|
5.0.9 / 2018-03-05
|
|
2
14
|
==================
|
|
3
15
|
* perf: bump mongodb -> 3.0.4 to fix SSL perf issue #6065
|
package/lib/cast.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
/*!
|
|
2
4
|
* Module dependencies.
|
|
3
5
|
*/
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const StrictModeError = require('./error/strict');
|
|
8
|
+
const Types = require('./schema/index');
|
|
9
|
+
const get = require('lodash.get');
|
|
10
|
+
const util = require('util');
|
|
11
|
+
const utils = require('./utils');
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
const ALLOWED_GEOWITHIN_GEOJSON_TYPES = ['Polygon', 'MultiPolygon'];
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* Handles internal casting for query filters.
|
|
@@ -67,6 +70,31 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
67
70
|
|
|
68
71
|
schematype = schema.path(path);
|
|
69
72
|
|
|
73
|
+
// Check for embedded discriminator paths
|
|
74
|
+
if (!schematype) {
|
|
75
|
+
let split = path.split('.');
|
|
76
|
+
let j = split.length;
|
|
77
|
+
while (j--) {
|
|
78
|
+
let pathFirstHalf = split.slice(0, j).join('.');
|
|
79
|
+
let pathLastHalf = split.slice(j).join('.');
|
|
80
|
+
let _schematype = schema.path(pathFirstHalf);
|
|
81
|
+
let discriminatorKey = get(_schematype, 'schema.options.discriminatorKey');
|
|
82
|
+
// gh-6027: if we haven't found the schematype but this path is
|
|
83
|
+
// underneath an embedded discriminator and the embedded discriminator
|
|
84
|
+
// key is in the query, use the embedded discriminator schema
|
|
85
|
+
if (_schematype != null &&
|
|
86
|
+
get(_schematype, 'schema.discriminators') != null &&
|
|
87
|
+
discriminatorKey != null &&
|
|
88
|
+
pathLastHalf !== discriminatorKey) {
|
|
89
|
+
const discriminatorVal = get(obj, pathFirstHalf + '.' + discriminatorKey);
|
|
90
|
+
if (discriminatorVal) {
|
|
91
|
+
schematype = _schematype.schema.discriminators[discriminatorVal].
|
|
92
|
+
path(pathLastHalf);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
70
98
|
if (!schematype) {
|
|
71
99
|
// Handle potential embedded array queries
|
|
72
100
|
var split = path.split('.'),
|
|
@@ -206,7 +234,7 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
206
234
|
} else if (options.strictQuery) {
|
|
207
235
|
delete obj[path];
|
|
208
236
|
}
|
|
209
|
-
} else if (val
|
|
237
|
+
} else if (val == null) {
|
|
210
238
|
obj[path] = null;
|
|
211
239
|
continue;
|
|
212
240
|
} else if (val.constructor.name === 'Object') {
|
package/lib/document.js
CHANGED
|
@@ -87,6 +87,10 @@ function Document(obj, fields, skipId, options) {
|
|
|
87
87
|
|
|
88
88
|
this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren);
|
|
89
89
|
|
|
90
|
+
// By default, defaults get applied **before** setting initial values
|
|
91
|
+
// Re: gh-6155
|
|
92
|
+
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, true);
|
|
93
|
+
|
|
90
94
|
if (obj) {
|
|
91
95
|
if (obj instanceof Document) {
|
|
92
96
|
this.isNew = obj.isNew;
|
|
@@ -99,7 +103,10 @@ function Document(obj, fields, skipId, options) {
|
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
|
|
102
|
-
|
|
106
|
+
// Function defaults get applied **after** setting initial values so they
|
|
107
|
+
// see the full doc rather than an empty one, unless they opt out.
|
|
108
|
+
// Re: gh-3781, gh-6155
|
|
109
|
+
$__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false);
|
|
103
110
|
|
|
104
111
|
this.$__._id = this._id;
|
|
105
112
|
|
|
@@ -202,7 +209,7 @@ function $__hasIncludedChildren(fields) {
|
|
|
202
209
|
* ignore
|
|
203
210
|
*/
|
|
204
211
|
|
|
205
|
-
function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren) {
|
|
212
|
+
function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters) {
|
|
206
213
|
const paths = Object.keys(doc.schema.paths);
|
|
207
214
|
const plen = paths.length;
|
|
208
215
|
|
|
@@ -222,6 +229,10 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren) {
|
|
|
222
229
|
let doc_ = doc._doc;
|
|
223
230
|
|
|
224
231
|
for (let j = 0; j < len; ++j) {
|
|
232
|
+
if (doc_ == null) {
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
|
|
225
236
|
let piece = path[j];
|
|
226
237
|
curPath += (!curPath.length ? '' : '.') + piece;
|
|
227
238
|
|
|
@@ -242,6 +253,18 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren) {
|
|
|
242
253
|
break;
|
|
243
254
|
}
|
|
244
255
|
|
|
256
|
+
if (typeof type.defaultValue === 'function') {
|
|
257
|
+
if (!type.defaultValue.$runBeforeSetters && isBeforeSetters) {
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
if (type.defaultValue.$runBeforeSetters && !isBeforeSetters) {
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
} else if (!isBeforeSetters) {
|
|
264
|
+
// Non-function defaults should always run **before** setters
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
|
|
245
268
|
if (fields && exclude !== null) {
|
|
246
269
|
if (exclude === true) {
|
|
247
270
|
// apply defaults to all non-excluded fields
|
package/lib/index.js
CHANGED
package/lib/query.js
CHANGED
|
@@ -2145,8 +2145,6 @@ Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
|
|
|
2145
2145
|
*/
|
|
2146
2146
|
|
|
2147
2147
|
Query.prototype._findOneAndUpdate = function(callback) {
|
|
2148
|
-
this._castConditions();
|
|
2149
|
-
|
|
2150
2148
|
if (this.error() != null) {
|
|
2151
2149
|
return callback(this.error());
|
|
2152
2150
|
}
|
|
@@ -2240,8 +2238,6 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
|
|
|
2240
2238
|
* @api private
|
|
2241
2239
|
*/
|
|
2242
2240
|
Query.prototype._findOneAndRemove = function(callback) {
|
|
2243
|
-
this._castConditions();
|
|
2244
|
-
|
|
2245
2241
|
if (this.error() != null) {
|
|
2246
2242
|
return callback(this.error());
|
|
2247
2243
|
}
|
package/lib/schema/array.js
CHANGED
|
@@ -94,7 +94,7 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
if (!('defaultValue' in this) || this.defaultValue !== void 0) {
|
|
97
|
-
|
|
97
|
+
var defaultFn = function() {
|
|
98
98
|
var arr = [];
|
|
99
99
|
if (fn) {
|
|
100
100
|
arr = defaultArr();
|
|
@@ -103,7 +103,9 @@ function SchemaArray(key, cast, options, schemaOptions) {
|
|
|
103
103
|
}
|
|
104
104
|
// Leave it up to `cast()` to convert the array
|
|
105
105
|
return arr;
|
|
106
|
-
}
|
|
106
|
+
};
|
|
107
|
+
defaultFn.$runBeforeSetters = true;
|
|
108
|
+
this.default(defaultFn);
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
package/lib/schema/embedded.js
CHANGED
|
@@ -152,7 +152,6 @@ Embedded.prototype.cast = function(val, doc, init, priorVal) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
|
|
156
155
|
var subdoc;
|
|
157
156
|
if (init) {
|
|
158
157
|
subdoc = new Constructor(void 0, doc ? doc.$__.selected : void 0, doc);
|
|
@@ -196,7 +195,22 @@ Embedded.prototype.castForQuery = function($conditional, val) {
|
|
|
196
195
|
val = this._applySetters(val);
|
|
197
196
|
}
|
|
198
197
|
|
|
199
|
-
|
|
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);
|
|
200
214
|
};
|
|
201
215
|
|
|
202
216
|
/**
|
package/lib/schema/objectid.js
CHANGED
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
|
package/migrating_to_5.md
CHANGED
|
@@ -33,6 +33,21 @@ mongoose.connect('mongodb://localhost:27017/test');
|
|
|
33
33
|
mongoose.model('Test', new Schema({}));
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
### Connection Logic and `useMongoClient`
|
|
37
|
+
|
|
38
|
+
The [`useMongoClient` option](http://mongoosejs.com/docs/4.x/docs/connections.html#use-mongo-client) was
|
|
39
|
+
removed in Mongoose 5, it is now always `true`. As a consequence, Mongoose 5
|
|
40
|
+
no longer supports several function signatures for `mongoose.connect()` that
|
|
41
|
+
worked in Mongoose 4.x if the `useMongoClient` option was off. Below are some
|
|
42
|
+
examples of `mongoose.connect()` calls that do **not** work in Mongoose 5.x.
|
|
43
|
+
|
|
44
|
+
* `mongoose.connect('localhost', 27017);`
|
|
45
|
+
* `mongoose.connect('localhost', 'mydb', 27017);`
|
|
46
|
+
* `mongoose.connect('mongodb://host1:27017,mongodb://host2:27017');`
|
|
47
|
+
|
|
48
|
+
In Mongoose 5.x, the first parameter to `mongoose.connect()` and `mongoose.createConnection()`, if specified, **must** be a [MongoDB connection string](https://docs.mongodb.com/manual/reference/connection-string/). The
|
|
49
|
+
connection string and options are then passed down to [the MongoDB Node.js driver's `MongoClient.connect()` function](http://mongodb.github.io/node-mongodb-native/3.0/api/MongoClient.html#.connect). Mongoose does not modify the connection string, although `mongoose.connect()` and `mongoose.createConnection()` support a [few additional options in addition to the ones the MongoDB driver supports](http://mongoosejs.com/docs/connections.html#options).
|
|
50
|
+
|
|
36
51
|
### Setter Order
|
|
37
52
|
|
|
38
53
|
Setters run in reverse order in 4.x:
|