mongoose 5.0.18 → 5.1.0
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 +4 -3
- package/History.md +16 -0
- package/lib/document.js +68 -12
- package/lib/drivers/browser/objectid.js +12 -0
- package/lib/drivers/node-mongodb-native/collection.js +10 -3
- package/lib/error/version.js +3 -2
- package/lib/index.js +10 -5
- package/lib/internal.js +1 -0
- package/lib/model.js +239 -36
- package/lib/plugins/saveSubdocs.js +1 -1
- package/lib/query.js +191 -97
- package/lib/queryhelpers.js +25 -23
- package/lib/schema/array.js +6 -3
- package/lib/schema/embedded.js +15 -9
- package/lib/schema/index.js +2 -0
- package/lib/schema/map.js +29 -0
- package/lib/schema/objectid.js +0 -20
- package/lib/schema.js +47 -9
- package/lib/schematype.js +19 -1
- package/lib/services/model/applyMethods.js +14 -4
- package/lib/services/query/completeMany.js +47 -0
- package/lib/types/embedded.js +33 -1
- package/lib/types/index.js +2 -0
- package/lib/types/map.js +144 -0
- package/lib/types/objectid.js +12 -0
- package/lib/types/subdocument.js +30 -1
- package/lib/utils.js +5 -3
- package/package.json +1 -1
package/lib/query.js
CHANGED
|
@@ -10,6 +10,7 @@ const QueryCursor = require('./cursor/QueryCursor');
|
|
|
10
10
|
const ReadPreference = require('./drivers').ReadPreference;
|
|
11
11
|
const cast = require('./cast');
|
|
12
12
|
const castUpdate = require('./services/query/castUpdate');
|
|
13
|
+
const completeMany = require('./services/query/completeMany');
|
|
13
14
|
const get = require('lodash.get');
|
|
14
15
|
const hasDollarKeys = require('./services/query/hasDollarKeys');
|
|
15
16
|
const helpers = require('./queryhelpers');
|
|
@@ -996,6 +997,7 @@ Query.prototype.read = function read(pref, tags) {
|
|
|
996
997
|
*
|
|
997
998
|
* The following options are for all operations:
|
|
998
999
|
* - [collation](https://docs.mongodb.com/manual/reference/collation/)
|
|
1000
|
+
* - [session](https://docs.mongodb.com/manual/reference/server-sessions/)
|
|
999
1001
|
*
|
|
1000
1002
|
* @param {Object} options
|
|
1001
1003
|
* @api public
|
|
@@ -1082,6 +1084,11 @@ Query.prototype.getUpdate = function() {
|
|
|
1082
1084
|
* @receiver Query
|
|
1083
1085
|
*/
|
|
1084
1086
|
|
|
1087
|
+
Query.prototype._fieldsForExec = function() {
|
|
1088
|
+
return utils.clone(this._fields);
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
|
|
1085
1092
|
/**
|
|
1086
1093
|
* Return an update document with corrected $set operations.
|
|
1087
1094
|
*
|
|
@@ -1308,10 +1315,16 @@ Query.prototype._find = function(callback) {
|
|
|
1308
1315
|
this._applyPaths();
|
|
1309
1316
|
this._fields = this._castFields(this._fields);
|
|
1310
1317
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1318
|
+
const fields = this._fieldsForExec();
|
|
1319
|
+
const mongooseOptions = this._mongooseOptions;
|
|
1320
|
+
const _this = this;
|
|
1321
|
+
const userProvidedFields = _this._userProvidedFields || {};
|
|
1322
|
+
|
|
1323
|
+
// Separate options to pass down to `completeMany()` in case we need to
|
|
1324
|
+
// set a session on the document
|
|
1325
|
+
const completeManyOptions = Object.assign({}, {
|
|
1326
|
+
session: get(this, 'options.session', null)
|
|
1327
|
+
});
|
|
1315
1328
|
|
|
1316
1329
|
var cb = function(err, docs) {
|
|
1317
1330
|
if (err) {
|
|
@@ -1325,16 +1338,17 @@ Query.prototype._find = function(callback) {
|
|
|
1325
1338
|
if (!mongooseOptions.populate) {
|
|
1326
1339
|
return !!mongooseOptions.lean === true
|
|
1327
1340
|
? callback(null, docs)
|
|
1328
|
-
: completeMany(_this.model, docs, fields, userProvidedFields,
|
|
1341
|
+
: completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions, callback);
|
|
1329
1342
|
}
|
|
1330
1343
|
|
|
1331
|
-
|
|
1344
|
+
const pop = helpers.preparePopulationOptionsMQ(_this, mongooseOptions);
|
|
1332
1345
|
pop.__noPromise = true;
|
|
1346
|
+
completeManyOptions.populated = pop;
|
|
1333
1347
|
_this.model.populate(docs, pop, function(err, docs) {
|
|
1334
1348
|
if (err) return callback(err);
|
|
1335
1349
|
return !!mongooseOptions.lean === true
|
|
1336
1350
|
? callback(null, docs)
|
|
1337
|
-
: completeMany(_this.model, docs, fields, userProvidedFields,
|
|
1351
|
+
: completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions, callback);
|
|
1338
1352
|
});
|
|
1339
1353
|
};
|
|
1340
1354
|
|
|
@@ -1436,43 +1450,6 @@ Query.prototype.merge = function(source) {
|
|
|
1436
1450
|
return this;
|
|
1437
1451
|
};
|
|
1438
1452
|
|
|
1439
|
-
/*!
|
|
1440
|
-
* hydrates many documents
|
|
1441
|
-
*
|
|
1442
|
-
* @param {Model} model
|
|
1443
|
-
* @param {Array} docs
|
|
1444
|
-
* @param {Object} fields
|
|
1445
|
-
* @param {Query} self
|
|
1446
|
-
* @param {Array} [pop] array of paths used in population
|
|
1447
|
-
* @param {Function} callback
|
|
1448
|
-
*/
|
|
1449
|
-
|
|
1450
|
-
function completeMany(model, docs, fields, userProvidedFields, pop, callback) {
|
|
1451
|
-
var arr = [];
|
|
1452
|
-
var count = docs.length;
|
|
1453
|
-
var len = count;
|
|
1454
|
-
var opts = pop ? { populated: pop } : undefined;
|
|
1455
|
-
var error = null;
|
|
1456
|
-
function init(_error) {
|
|
1457
|
-
if (_error != null) {
|
|
1458
|
-
error = error || _error;
|
|
1459
|
-
}
|
|
1460
|
-
if (error != null) {
|
|
1461
|
-
--count || process.nextTick(() => callback(error));
|
|
1462
|
-
return;
|
|
1463
|
-
}
|
|
1464
|
-
--count || process.nextTick(() => callback(error, arr));
|
|
1465
|
-
}
|
|
1466
|
-
for (var i = 0; i < len; ++i) {
|
|
1467
|
-
arr[i] = helpers.createModel(model, docs[i], fields, userProvidedFields);
|
|
1468
|
-
try {
|
|
1469
|
-
arr[i].init(docs[i], opts, init);
|
|
1470
|
-
} catch (error) {
|
|
1471
|
-
init(error);
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
1453
|
/**
|
|
1477
1454
|
* Adds a collation to this op (MongoDB 3.4 and up)
|
|
1478
1455
|
*
|
|
@@ -1490,6 +1467,44 @@ Query.prototype.collation = function(value) {
|
|
|
1490
1467
|
return this;
|
|
1491
1468
|
};
|
|
1492
1469
|
|
|
1470
|
+
/**
|
|
1471
|
+
* Hydrate a single doc from `findOne()`, `findOneAndUpdate()`, etc.
|
|
1472
|
+
*
|
|
1473
|
+
* @api private
|
|
1474
|
+
*/
|
|
1475
|
+
|
|
1476
|
+
Query.prototype._completeOne = function(doc, res, callback) {
|
|
1477
|
+
if (!doc) {
|
|
1478
|
+
return callback(null, null);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
const model = this.model;
|
|
1482
|
+
const projection = utils.clone(this._fields);
|
|
1483
|
+
const userProvidedFields = this._userProvidedFields || {};
|
|
1484
|
+
// `populate`, `lean`
|
|
1485
|
+
const mongooseOptions = this._mongooseOptions;
|
|
1486
|
+
// `rawResult`
|
|
1487
|
+
const options = this.options;
|
|
1488
|
+
|
|
1489
|
+
if (!mongooseOptions.populate) {
|
|
1490
|
+
return mongooseOptions.lean ?
|
|
1491
|
+
_completeOneLean(doc, res, options, callback) :
|
|
1492
|
+
completeOne(model, doc, res, options, projection, userProvidedFields,
|
|
1493
|
+
null, callback);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
const pop = helpers.preparePopulationOptionsMQ(this, this._mongooseOptions);
|
|
1497
|
+
model.populate(doc, pop, (err, doc) => {
|
|
1498
|
+
if (err) {
|
|
1499
|
+
return callback(err);
|
|
1500
|
+
}
|
|
1501
|
+
return mongooseOptions.lean ?
|
|
1502
|
+
_completeOneLean(doc, res, options, callback) :
|
|
1503
|
+
completeOne(model, doc, res, options, projection, userProvidedFields,
|
|
1504
|
+
pop, callback);
|
|
1505
|
+
});
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1493
1508
|
/**
|
|
1494
1509
|
* Thunk around findOne()
|
|
1495
1510
|
*
|
|
@@ -1508,36 +1523,13 @@ Query.prototype._findOne = function(callback) {
|
|
|
1508
1523
|
this._applyPaths();
|
|
1509
1524
|
this._fields = this._castFields(this._fields);
|
|
1510
1525
|
|
|
1511
|
-
var options = this._mongooseOptions;
|
|
1512
|
-
var projection = this._fieldsForExec();
|
|
1513
|
-
var userProvidedFields = this._userProvidedFields || {};
|
|
1514
|
-
var _this = this;
|
|
1515
|
-
|
|
1516
1526
|
// don't pass in the conditions because we already merged them in
|
|
1517
|
-
Query.base.findOne.call(
|
|
1527
|
+
Query.base.findOne.call(this, {}, (err, doc) => {
|
|
1518
1528
|
if (err) {
|
|
1519
1529
|
return callback(err);
|
|
1520
1530
|
}
|
|
1521
|
-
if (!doc) {
|
|
1522
|
-
return callback(null, null);
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
if (!options.populate) {
|
|
1526
|
-
return !!options.lean === true
|
|
1527
|
-
? callback(null, doc)
|
|
1528
|
-
: completeOne(_this.model, doc, null, {}, projection, userProvidedFields, null, callback);
|
|
1529
|
-
}
|
|
1530
1531
|
|
|
1531
|
-
|
|
1532
|
-
pop.__noPromise = true;
|
|
1533
|
-
_this.model.populate(doc, pop, function(err, doc) {
|
|
1534
|
-
if (err) {
|
|
1535
|
-
return callback(err);
|
|
1536
|
-
}
|
|
1537
|
-
return !!options.lean === true
|
|
1538
|
-
? callback(null, doc)
|
|
1539
|
-
: completeOne(_this.model, doc, null, {}, projection, userProvidedFields, pop, callback);
|
|
1540
|
-
});
|
|
1532
|
+
this._completeOne(doc, null, callback);
|
|
1541
1533
|
});
|
|
1542
1534
|
};
|
|
1543
1535
|
|
|
@@ -2015,6 +2007,8 @@ function completeOne(model, doc, res, options, fields, userProvidedFields, pop,
|
|
|
2015
2007
|
return process.nextTick(() => callback(err));
|
|
2016
2008
|
}
|
|
2017
2009
|
|
|
2010
|
+
casted.$session(options.session);
|
|
2011
|
+
|
|
2018
2012
|
if (options.rawResult) {
|
|
2019
2013
|
res.value = casted;
|
|
2020
2014
|
return process.nextTick(() => callback(null, res));
|
|
@@ -2247,6 +2241,130 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
|
|
|
2247
2241
|
return this;
|
|
2248
2242
|
};
|
|
2249
2243
|
|
|
2244
|
+
/**
|
|
2245
|
+
* Issues a MongoDB [findOneAndDelete](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndDelete/) command.
|
|
2246
|
+
*
|
|
2247
|
+
* Finds a matching document, removes it, and passes the found document (if any) to the callback. Executes immediately if `callback` is passed.
|
|
2248
|
+
*
|
|
2249
|
+
* This function triggers the following middleware.
|
|
2250
|
+
*
|
|
2251
|
+
* - `findOneAndDelete()`
|
|
2252
|
+
*
|
|
2253
|
+
* This function differs slightly from `Model.findOneAndRemove()` in that
|
|
2254
|
+
* `findOneAndRemove()` becomes a [MongoDB `findAndModify()` command](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/),
|
|
2255
|
+
* as opposed to a `findOneAndDelete()` command. For most mongoose use cases,
|
|
2256
|
+
* this distinction is purely pedantic. You should use `findOneAndDelete()`
|
|
2257
|
+
* unless you have a good reason not to.
|
|
2258
|
+
*
|
|
2259
|
+
* ####Available options
|
|
2260
|
+
*
|
|
2261
|
+
* - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
|
|
2262
|
+
* - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
|
|
2263
|
+
* - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
|
|
2264
|
+
*
|
|
2265
|
+
* ####Callback Signature
|
|
2266
|
+
* function(error, doc) {
|
|
2267
|
+
* // error: any errors that occurred
|
|
2268
|
+
* // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
|
|
2269
|
+
* }
|
|
2270
|
+
*
|
|
2271
|
+
* ####Examples
|
|
2272
|
+
*
|
|
2273
|
+
* A.where().findOneAndDelete(conditions, options, callback) // executes
|
|
2274
|
+
* A.where().findOneAndDelete(conditions, options) // return Query
|
|
2275
|
+
* A.where().findOneAndDelete(conditions, callback) // executes
|
|
2276
|
+
* A.where().findOneAndDelete(conditions) // returns Query
|
|
2277
|
+
* A.where().findOneAndDelete(callback) // executes
|
|
2278
|
+
* A.where().findOneAndDelete() // returns Query
|
|
2279
|
+
*
|
|
2280
|
+
* @method findOneAndDelete
|
|
2281
|
+
* @memberOf Query
|
|
2282
|
+
* @param {Object} [conditions]
|
|
2283
|
+
* @param {Object} [options]
|
|
2284
|
+
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
|
|
2285
|
+
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
|
|
2286
|
+
* @param {Function} [callback] optional params are (error, document)
|
|
2287
|
+
* @return {Query} this
|
|
2288
|
+
* @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
|
|
2289
|
+
* @api public
|
|
2290
|
+
*/
|
|
2291
|
+
|
|
2292
|
+
Query.prototype.findOneAndDelete = function(conditions, options, callback) {
|
|
2293
|
+
this.op = 'findOneAndDelete';
|
|
2294
|
+
this._validate();
|
|
2295
|
+
|
|
2296
|
+
switch (arguments.length) {
|
|
2297
|
+
case 2:
|
|
2298
|
+
if (typeof options === 'function') {
|
|
2299
|
+
callback = options;
|
|
2300
|
+
options = {};
|
|
2301
|
+
}
|
|
2302
|
+
break;
|
|
2303
|
+
case 1:
|
|
2304
|
+
if (typeof conditions === 'function') {
|
|
2305
|
+
callback = conditions;
|
|
2306
|
+
conditions = undefined;
|
|
2307
|
+
options = undefined;
|
|
2308
|
+
}
|
|
2309
|
+
break;
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
if (mquery.canMerge(conditions)) {
|
|
2313
|
+
this.merge(conditions);
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
options && this.setOptions(options);
|
|
2317
|
+
|
|
2318
|
+
if (!callback) {
|
|
2319
|
+
return this;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
this._findOneAndDelete(callback);
|
|
2323
|
+
|
|
2324
|
+
return this;
|
|
2325
|
+
};
|
|
2326
|
+
|
|
2327
|
+
/*!
|
|
2328
|
+
* Thunk around findOneAndDelete()
|
|
2329
|
+
*
|
|
2330
|
+
* @param {Function} [callback]
|
|
2331
|
+
* @return {Query} this
|
|
2332
|
+
* @api private
|
|
2333
|
+
*/
|
|
2334
|
+
Query.prototype._findOneAndDelete = function(callback) {
|
|
2335
|
+
this._castConditions();
|
|
2336
|
+
|
|
2337
|
+
if (this.error() != null) {
|
|
2338
|
+
callback(this.error());
|
|
2339
|
+
return this;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
const filter = this._conditions;
|
|
2343
|
+
const options = this._optionsForExec();
|
|
2344
|
+
let fields = null;
|
|
2345
|
+
|
|
2346
|
+
if (this._fields != null) {
|
|
2347
|
+
options.projection = this._castFields(utils.clone(this._fields));
|
|
2348
|
+
fields = options.projection;
|
|
2349
|
+
if (fields instanceof Error) {
|
|
2350
|
+
callback(fields);
|
|
2351
|
+
return this;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
this._collection.collection.findOneAndDelete(filter, options, (err, res) => {
|
|
2356
|
+
if (err) {
|
|
2357
|
+
return callback(err);
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
const doc = res.value;
|
|
2361
|
+
|
|
2362
|
+
return this._completeOne(doc, res, callback);
|
|
2363
|
+
});
|
|
2364
|
+
|
|
2365
|
+
return this;
|
|
2366
|
+
};
|
|
2367
|
+
|
|
2250
2368
|
/*!
|
|
2251
2369
|
* Thunk around findOneAndRemove()
|
|
2252
2370
|
*
|
|
@@ -2259,7 +2377,9 @@ Query.prototype._findOneAndRemove = function(callback) {
|
|
|
2259
2377
|
return callback(this.error());
|
|
2260
2378
|
}
|
|
2261
2379
|
|
|
2262
|
-
|
|
2380
|
+
this._findAndModify('remove', callback);
|
|
2381
|
+
|
|
2382
|
+
return this;
|
|
2263
2383
|
};
|
|
2264
2384
|
|
|
2265
2385
|
/*!
|
|
@@ -2346,7 +2466,6 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
2346
2466
|
}
|
|
2347
2467
|
|
|
2348
2468
|
this._applyPaths();
|
|
2349
|
-
var userProvidedFields = this._userProvidedFields || {};
|
|
2350
2469
|
|
|
2351
2470
|
var options = this._mongooseOptions;
|
|
2352
2471
|
|
|
@@ -2365,32 +2484,7 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
2365
2484
|
return callback(err);
|
|
2366
2485
|
}
|
|
2367
2486
|
|
|
2368
|
-
|
|
2369
|
-
if (opts.rawResult) {
|
|
2370
|
-
return callback(null, res);
|
|
2371
|
-
}
|
|
2372
|
-
return callback(null, null);
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
if (!options.populate) {
|
|
2376
|
-
if (!!options.lean === true) {
|
|
2377
|
-
return _completeOneLean(doc, res, opts, callback);
|
|
2378
|
-
}
|
|
2379
|
-
return completeOne(_this.model, doc, res, opts, fields, userProvidedFields, null, callback);
|
|
2380
|
-
}
|
|
2381
|
-
|
|
2382
|
-
var pop = helpers.preparePopulationOptionsMQ(_this, options);
|
|
2383
|
-
pop.__noPromise = true;
|
|
2384
|
-
_this.model.populate(doc, pop, function(err, doc) {
|
|
2385
|
-
if (err) {
|
|
2386
|
-
return callback(err);
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2389
|
-
if (!!options.lean === true) {
|
|
2390
|
-
return _completeOneLean(doc, res, opts, callback);
|
|
2391
|
-
}
|
|
2392
|
-
return completeOne(_this.model, doc, res, opts, fields, userProvidedFields, pop, callback);
|
|
2393
|
-
});
|
|
2487
|
+
_this._completeOne(doc, res, callback);
|
|
2394
2488
|
};
|
|
2395
2489
|
|
|
2396
2490
|
var _callback;
|
package/lib/queryhelpers.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Module dependencies
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const get = require('lodash.get');
|
|
8
|
+
const isDefiningProjection = require('./services/projection/isDefiningProjection');
|
|
9
|
+
const utils = require('./utils');
|
|
10
10
|
|
|
11
11
|
/*!
|
|
12
12
|
* Prepare a set of path options for query population.
|
|
@@ -17,7 +17,7 @@ var utils = require('./utils');
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
exports.preparePopulationOptions = function preparePopulationOptions(query, options) {
|
|
20
|
-
|
|
20
|
+
const pop = utils.object.vals(query.options.populate);
|
|
21
21
|
|
|
22
22
|
// lean options should trickle through all queries
|
|
23
23
|
if (options.lean) {
|
|
@@ -37,7 +37,7 @@ exports.preparePopulationOptions = function preparePopulationOptions(query, opti
|
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query, options) {
|
|
40
|
-
|
|
40
|
+
const pop = utils.object.vals(query._mongooseOptions.populate);
|
|
41
41
|
|
|
42
42
|
// lean options should trickle through all queries
|
|
43
43
|
if (options.lean) {
|
|
@@ -55,12 +55,12 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
|
|
|
55
55
|
* @param {string} value
|
|
56
56
|
*/
|
|
57
57
|
function getDiscriminatorByValue(model, value) {
|
|
58
|
-
|
|
58
|
+
let discriminator = null;
|
|
59
59
|
if (!model.discriminators) {
|
|
60
60
|
return discriminator;
|
|
61
61
|
}
|
|
62
|
-
for (
|
|
63
|
-
|
|
62
|
+
for (const name in model.discriminators) {
|
|
63
|
+
const it = model.discriminators[name];
|
|
64
64
|
if (
|
|
65
65
|
it.schema &&
|
|
66
66
|
it.schema.discriminatorMapping &&
|
|
@@ -123,7 +123,9 @@ function gatherPaths(obj, map, path) {
|
|
|
123
123
|
if (obj[key] != null &&
|
|
124
124
|
typeof obj[key] === 'object' &&
|
|
125
125
|
!Array.isArray(obj) &&
|
|
126
|
-
!obj
|
|
126
|
+
!(obj instanceof Map) &&
|
|
127
|
+
!obj[key]._bsontype &&
|
|
128
|
+
!utils.isMongooseObject(obj[key])) {
|
|
127
129
|
gatherPaths(obj[key], map, fullPath);
|
|
128
130
|
}
|
|
129
131
|
}
|
|
@@ -137,10 +139,10 @@ function gatherPaths(obj, map, path) {
|
|
|
137
139
|
|
|
138
140
|
exports.applyPaths = function applyPaths(fields, schema) {
|
|
139
141
|
// determine if query is selecting or excluding fields
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
let exclude;
|
|
143
|
+
let keys;
|
|
144
|
+
let ki;
|
|
145
|
+
let field;
|
|
144
146
|
|
|
145
147
|
if (fields) {
|
|
146
148
|
keys = Object.keys(fields);
|
|
@@ -163,11 +165,11 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
163
165
|
// if selecting, apply default schematype select:true fields
|
|
164
166
|
// if excluding, apply schematype select:false fields
|
|
165
167
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
let selected = [];
|
|
169
|
+
let excluded = [];
|
|
170
|
+
let stack = [];
|
|
169
171
|
|
|
170
|
-
|
|
172
|
+
let analyzePath = function(path, type) {
|
|
171
173
|
if (typeof type.selected !== 'boolean') return;
|
|
172
174
|
|
|
173
175
|
var plusPath = '+' + path;
|
|
@@ -185,8 +187,8 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
// check for parent exclusions
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
let pieces = path.split('.');
|
|
191
|
+
let root = pieces[0];
|
|
190
192
|
if (~excluded.indexOf(root)) {
|
|
191
193
|
return;
|
|
192
194
|
}
|
|
@@ -195,10 +197,10 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
195
197
|
// don't explicitly project in the discriminator key because that will
|
|
196
198
|
// project out everything else under the parent path
|
|
197
199
|
if (!exclude && get(type, 'options.$skipDiscriminatorCheck', false)) {
|
|
198
|
-
|
|
199
|
-
for (
|
|
200
|
+
let cur = '';
|
|
201
|
+
for (let i = 0; i < pieces.length; ++i) {
|
|
200
202
|
cur += (cur.length === 0 ? '' : '.') + pieces[i];
|
|
201
|
-
|
|
203
|
+
const projection = get(fields, cur, false);
|
|
202
204
|
if (projection && typeof projection !== 'object') {
|
|
203
205
|
return;
|
|
204
206
|
}
|
|
@@ -233,7 +235,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
233
235
|
|
|
234
236
|
analyzeSchema(schema);
|
|
235
237
|
|
|
236
|
-
|
|
238
|
+
let i;
|
|
237
239
|
switch (exclude) {
|
|
238
240
|
case true:
|
|
239
241
|
for (i = 0; i < excluded.length; ++i) {
|
package/lib/schema/array.js
CHANGED
|
@@ -221,8 +221,8 @@ SchemaArray.prototype.cast = function(value, doc, init) {
|
|
|
221
221
|
*/
|
|
222
222
|
|
|
223
223
|
SchemaArray.prototype.castForQuery = function($conditional, value) {
|
|
224
|
-
var handler
|
|
225
|
-
|
|
224
|
+
var handler;
|
|
225
|
+
var val;
|
|
226
226
|
|
|
227
227
|
if (arguments.length === 2) {
|
|
228
228
|
handler = this.$conditionalHandlers[$conditional];
|
|
@@ -355,13 +355,16 @@ handle.$type = $type;
|
|
|
355
355
|
handle.$eq =
|
|
356
356
|
handle.$gt =
|
|
357
357
|
handle.$gte =
|
|
358
|
-
handle.$in =
|
|
359
358
|
handle.$lt =
|
|
360
359
|
handle.$lte =
|
|
361
360
|
handle.$ne =
|
|
362
361
|
handle.$nin =
|
|
363
362
|
handle.$regex = SchemaArray.prototype.castForQuery;
|
|
364
363
|
|
|
364
|
+
// `$in` is special because you can also include an empty array in the query
|
|
365
|
+
// like `$in: [1, []]`, see gh-5913
|
|
366
|
+
handle.$in = SchemaType.prototype.$conditionalHandlers.$in;
|
|
367
|
+
|
|
365
368
|
/*!
|
|
366
369
|
* Module exports.
|
|
367
370
|
*/
|
package/lib/schema/embedded.js
CHANGED
|
@@ -219,7 +219,7 @@ Embedded.prototype.castForQuery = function($conditional, val) {
|
|
|
219
219
|
* @api private
|
|
220
220
|
*/
|
|
221
221
|
|
|
222
|
-
Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
222
|
+
Embedded.prototype.doValidate = function(value, fn, scope, options) {
|
|
223
223
|
var Constructor = this.caster;
|
|
224
224
|
var discriminatorKey = Constructor.schema.options.discriminatorKey;
|
|
225
225
|
if (value != null &&
|
|
@@ -235,6 +235,13 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
if (options && options.skipSchemaValidators) {
|
|
239
|
+
if (!(value instanceof Constructor)) {
|
|
240
|
+
value = new Constructor(value, null, scope);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return value.validate(fn);
|
|
244
|
+
}
|
|
238
245
|
|
|
239
246
|
SchemaType.prototype.doValidate.call(this, value, function(error) {
|
|
240
247
|
if (error) {
|
|
@@ -244,10 +251,7 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
244
251
|
return fn(null);
|
|
245
252
|
}
|
|
246
253
|
|
|
247
|
-
|
|
248
|
-
value = new Constructor(value);
|
|
249
|
-
}
|
|
250
|
-
value.validate({__noPromise: true}, fn);
|
|
254
|
+
value.validate(fn);
|
|
251
255
|
}, scope);
|
|
252
256
|
};
|
|
253
257
|
|
|
@@ -257,10 +261,12 @@ Embedded.prototype.doValidate = function(value, fn, scope) {
|
|
|
257
261
|
* @api private
|
|
258
262
|
*/
|
|
259
263
|
|
|
260
|
-
Embedded.prototype.doValidateSync = function(value, scope) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
+
Embedded.prototype.doValidateSync = function(value, scope, options) {
|
|
265
|
+
if (!options || !options.skipSchemaValidators) {
|
|
266
|
+
var schemaTypeError = SchemaType.prototype.doValidateSync.call(this, value, scope);
|
|
267
|
+
if (schemaTypeError) {
|
|
268
|
+
return schemaTypeError;
|
|
269
|
+
}
|
|
264
270
|
}
|
|
265
271
|
if (!value) {
|
|
266
272
|
return;
|
package/lib/schema/index.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* ignore
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const MongooseMap = require('../types/map');
|
|
8
|
+
const SchemaType = require('../schematype');
|
|
9
|
+
|
|
10
|
+
/*!
|
|
11
|
+
* ignore
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
class SchemaMap extends SchemaType {
|
|
15
|
+
constructor(key, options) {
|
|
16
|
+
super(key, options, 'Map');
|
|
17
|
+
this.$isSchemaMap = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
cast(val, doc) {
|
|
21
|
+
if (val instanceof MongooseMap) {
|
|
22
|
+
return val;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return new MongooseMap(val, this.path, doc, this.$__schemaType);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = SchemaMap;
|
package/lib/schema/objectid.js
CHANGED
|
@@ -178,26 +178,6 @@ ObjectId.prototype.$conditionalHandlers =
|
|
|
178
178
|
$lte: handleSingle
|
|
179
179
|
});
|
|
180
180
|
|
|
181
|
-
/**
|
|
182
|
-
* Casts contents for queries.
|
|
183
|
-
*
|
|
184
|
-
* @param {String} $conditional
|
|
185
|
-
* @param {any} [val]
|
|
186
|
-
* @api private
|
|
187
|
-
*/
|
|
188
|
-
|
|
189
|
-
ObjectId.prototype.castForQuery = function($conditional, val) {
|
|
190
|
-
var handler;
|
|
191
|
-
if (arguments.length === 2) {
|
|
192
|
-
handler = this.$conditionalHandlers[$conditional];
|
|
193
|
-
if (!handler) {
|
|
194
|
-
throw new Error('Can\'t use ' + $conditional + ' with ObjectId.');
|
|
195
|
-
}
|
|
196
|
-
return handler.call(this, val);
|
|
197
|
-
}
|
|
198
|
-
return this._castForQuery($conditional);
|
|
199
|
-
};
|
|
200
|
-
|
|
201
181
|
/*!
|
|
202
182
|
* ignore
|
|
203
183
|
*/
|