mongoose 5.0.17 → 5.1.2
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 +61 -0
- package/lib/aggregate.js +15 -4
- package/lib/connection.js +12 -0
- package/lib/document.js +79 -18
- package/lib/drivers/browser/objectid.js +12 -0
- package/lib/drivers/node-mongodb-native/collection.js +46 -35
- package/lib/error/version.js +4 -2
- package/lib/index.js +12 -7
- package/lib/internal.js +1 -0
- package/lib/model.js +329 -96
- package/lib/plugins/idGetter.js +0 -12
- package/lib/plugins/saveSubdocs.js +1 -1
- package/lib/query.js +202 -109
- package/lib/queryhelpers.js +59 -32
- package/lib/schema/array.js +6 -3
- package/lib/schema/date.js +5 -2
- package/lib/schema/decimal128.js +4 -0
- 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 +49 -9
- package/lib/schematype.js +19 -1
- package/lib/services/model/applyHooks.js +22 -2
- package/lib/services/model/applyMethods.js +14 -4
- package/lib/services/populate/getVirtual.js +4 -0
- package/lib/services/query/castUpdate.js +1 -1
- package/lib/services/query/completeMany.js +47 -0
- package/lib/types/buffer.js +1 -1
- package/lib/types/documentarray.js +16 -2
- package/lib/types/embedded.js +33 -1
- package/lib/types/index.js +2 -0
- package/lib/types/map.js +149 -0
- package/lib/types/objectid.js +12 -0
- package/lib/types/subdocument.js +30 -1
- package/lib/utils.js +49 -6
- package/migrating_to_5.md +1 -1
- package/package.json +5 -5
package/lib/plugins/idGetter.js
CHANGED
|
@@ -13,18 +13,6 @@ module.exports = function(schema) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
schema.virtual('id').get(idGetter);
|
|
16
|
-
|
|
17
|
-
if ('toHexString' in schema.methods) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Re: gh-6115, make it easy to get something usable as an ObjectID regardless
|
|
22
|
-
// of whether a property is populated or not. With this, you can do
|
|
23
|
-
// `blogPost.author.toHexString()` and get a hex string regardless of whether
|
|
24
|
-
// `author` is populated
|
|
25
|
-
schema.methods.toHexString = function() {
|
|
26
|
-
return this.id;
|
|
27
|
-
};
|
|
28
16
|
};
|
|
29
17
|
|
|
30
18
|
/*!
|
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');
|
|
@@ -166,7 +167,7 @@ Query.prototype.toConstructor = function toConstructor() {
|
|
|
166
167
|
Query.call(this, criteria, options || null, model, coll);
|
|
167
168
|
};
|
|
168
169
|
|
|
169
|
-
util.inherits(CustomQuery, Query);
|
|
170
|
+
util.inherits(CustomQuery, model.Query);
|
|
170
171
|
|
|
171
172
|
// set inherited defaults
|
|
172
173
|
var p = CustomQuery.prototype;
|
|
@@ -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
|
*
|
|
@@ -1302,16 +1309,22 @@ Query.prototype._find = function(callback) {
|
|
|
1302
1309
|
|
|
1303
1310
|
if (this.error() != null) {
|
|
1304
1311
|
callback(this.error());
|
|
1305
|
-
return
|
|
1312
|
+
return null;
|
|
1306
1313
|
}
|
|
1307
1314
|
|
|
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,23 +1338,25 @@ 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
|
|
|
1341
1355
|
var options = this._optionsForExec();
|
|
1342
1356
|
options.fields = this._fieldsForExec();
|
|
1343
1357
|
var filter = this._conditions;
|
|
1344
|
-
|
|
1358
|
+
this._collection.find(filter, options, cb);
|
|
1359
|
+
return null;
|
|
1345
1360
|
};
|
|
1346
1361
|
|
|
1347
1362
|
/**
|
|
@@ -1436,43 +1451,6 @@ Query.prototype.merge = function(source) {
|
|
|
1436
1451
|
return this;
|
|
1437
1452
|
};
|
|
1438
1453
|
|
|
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
1454
|
/**
|
|
1477
1455
|
* Adds a collation to this op (MongoDB 3.4 and up)
|
|
1478
1456
|
*
|
|
@@ -1490,6 +1468,44 @@ Query.prototype.collation = function(value) {
|
|
|
1490
1468
|
return this;
|
|
1491
1469
|
};
|
|
1492
1470
|
|
|
1471
|
+
/**
|
|
1472
|
+
* Hydrate a single doc from `findOne()`, `findOneAndUpdate()`, etc.
|
|
1473
|
+
*
|
|
1474
|
+
* @api private
|
|
1475
|
+
*/
|
|
1476
|
+
|
|
1477
|
+
Query.prototype._completeOne = function(doc, res, callback) {
|
|
1478
|
+
if (!doc) {
|
|
1479
|
+
return callback(null, null);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
const model = this.model;
|
|
1483
|
+
const projection = utils.clone(this._fields);
|
|
1484
|
+
const userProvidedFields = this._userProvidedFields || {};
|
|
1485
|
+
// `populate`, `lean`
|
|
1486
|
+
const mongooseOptions = this._mongooseOptions;
|
|
1487
|
+
// `rawResult`
|
|
1488
|
+
const options = this.options;
|
|
1489
|
+
|
|
1490
|
+
if (!mongooseOptions.populate) {
|
|
1491
|
+
return mongooseOptions.lean ?
|
|
1492
|
+
_completeOneLean(doc, res, options, callback) :
|
|
1493
|
+
completeOne(model, doc, res, options, projection, userProvidedFields,
|
|
1494
|
+
null, callback);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
const pop = helpers.preparePopulationOptionsMQ(this, this._mongooseOptions);
|
|
1498
|
+
model.populate(doc, pop, (err, doc) => {
|
|
1499
|
+
if (err) {
|
|
1500
|
+
return callback(err);
|
|
1501
|
+
}
|
|
1502
|
+
return mongooseOptions.lean ?
|
|
1503
|
+
_completeOneLean(doc, res, options, callback) :
|
|
1504
|
+
completeOne(model, doc, res, options, projection, userProvidedFields,
|
|
1505
|
+
pop, callback);
|
|
1506
|
+
});
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1493
1509
|
/**
|
|
1494
1510
|
* Thunk around findOne()
|
|
1495
1511
|
*
|
|
@@ -1502,42 +1518,21 @@ Query.prototype._findOne = function(callback) {
|
|
|
1502
1518
|
this._castConditions();
|
|
1503
1519
|
|
|
1504
1520
|
if (this.error()) {
|
|
1505
|
-
|
|
1521
|
+
callback(this.error());
|
|
1522
|
+
return null;
|
|
1506
1523
|
}
|
|
1507
1524
|
|
|
1508
1525
|
this._applyPaths();
|
|
1509
1526
|
this._fields = this._castFields(this._fields);
|
|
1510
1527
|
|
|
1511
|
-
var options = this._mongooseOptions;
|
|
1512
|
-
var projection = this._fieldsForExec();
|
|
1513
|
-
var userProvidedFields = this._userProvidedFields || {};
|
|
1514
|
-
var _this = this;
|
|
1515
|
-
|
|
1516
1528
|
// don't pass in the conditions because we already merged them in
|
|
1517
|
-
Query.base.findOne.call(
|
|
1529
|
+
Query.base.findOne.call(this, {}, (err, doc) => {
|
|
1518
1530
|
if (err) {
|
|
1519
|
-
|
|
1520
|
-
|
|
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);
|
|
1531
|
+
callback(err);
|
|
1532
|
+
return null;
|
|
1529
1533
|
}
|
|
1530
1534
|
|
|
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
|
-
});
|
|
1535
|
+
this._completeOne(doc, null, callback);
|
|
1541
1536
|
});
|
|
1542
1537
|
};
|
|
1543
1538
|
|
|
@@ -2015,6 +2010,8 @@ function completeOne(model, doc, res, options, fields, userProvidedFields, pop,
|
|
|
2015
2010
|
return process.nextTick(() => callback(err));
|
|
2016
2011
|
}
|
|
2017
2012
|
|
|
2013
|
+
casted.$session(options.session);
|
|
2014
|
+
|
|
2018
2015
|
if (options.rawResult) {
|
|
2019
2016
|
res.value = casted;
|
|
2020
2017
|
return process.nextTick(() => callback(null, res));
|
|
@@ -2167,7 +2164,6 @@ Query.prototype._findOneAndUpdate = function(callback) {
|
|
|
2167
2164
|
}
|
|
2168
2165
|
|
|
2169
2166
|
this._findAndModify('update', callback);
|
|
2170
|
-
return this;
|
|
2171
2167
|
};
|
|
2172
2168
|
|
|
2173
2169
|
/**
|
|
@@ -2247,6 +2243,128 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
|
|
|
2247
2243
|
return this;
|
|
2248
2244
|
};
|
|
2249
2245
|
|
|
2246
|
+
/**
|
|
2247
|
+
* Issues a MongoDB [findOneAndDelete](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndDelete/) command.
|
|
2248
|
+
*
|
|
2249
|
+
* Finds a matching document, removes it, and passes the found document (if any) to the callback. Executes immediately if `callback` is passed.
|
|
2250
|
+
*
|
|
2251
|
+
* This function triggers the following middleware.
|
|
2252
|
+
*
|
|
2253
|
+
* - `findOneAndDelete()`
|
|
2254
|
+
*
|
|
2255
|
+
* This function differs slightly from `Model.findOneAndRemove()` in that
|
|
2256
|
+
* `findOneAndRemove()` becomes a [MongoDB `findAndModify()` command](https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/),
|
|
2257
|
+
* as opposed to a `findOneAndDelete()` command. For most mongoose use cases,
|
|
2258
|
+
* this distinction is purely pedantic. You should use `findOneAndDelete()`
|
|
2259
|
+
* unless you have a good reason not to.
|
|
2260
|
+
*
|
|
2261
|
+
* ####Available options
|
|
2262
|
+
*
|
|
2263
|
+
* - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
|
|
2264
|
+
* - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
|
|
2265
|
+
* - `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)
|
|
2266
|
+
*
|
|
2267
|
+
* ####Callback Signature
|
|
2268
|
+
* function(error, doc) {
|
|
2269
|
+
* // error: any errors that occurred
|
|
2270
|
+
* // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
|
|
2271
|
+
* }
|
|
2272
|
+
*
|
|
2273
|
+
* ####Examples
|
|
2274
|
+
*
|
|
2275
|
+
* A.where().findOneAndDelete(conditions, options, callback) // executes
|
|
2276
|
+
* A.where().findOneAndDelete(conditions, options) // return Query
|
|
2277
|
+
* A.where().findOneAndDelete(conditions, callback) // executes
|
|
2278
|
+
* A.where().findOneAndDelete(conditions) // returns Query
|
|
2279
|
+
* A.where().findOneAndDelete(callback) // executes
|
|
2280
|
+
* A.where().findOneAndDelete() // returns Query
|
|
2281
|
+
*
|
|
2282
|
+
* @method findOneAndDelete
|
|
2283
|
+
* @memberOf Query
|
|
2284
|
+
* @param {Object} [conditions]
|
|
2285
|
+
* @param {Object} [options]
|
|
2286
|
+
* @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)
|
|
2287
|
+
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](http://mongoosejs.com/docs/guide.html#strict)
|
|
2288
|
+
* @param {Function} [callback] optional params are (error, document)
|
|
2289
|
+
* @return {Query} this
|
|
2290
|
+
* @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command
|
|
2291
|
+
* @api public
|
|
2292
|
+
*/
|
|
2293
|
+
|
|
2294
|
+
Query.prototype.findOneAndDelete = function(conditions, options, callback) {
|
|
2295
|
+
this.op = 'findOneAndDelete';
|
|
2296
|
+
this._validate();
|
|
2297
|
+
|
|
2298
|
+
switch (arguments.length) {
|
|
2299
|
+
case 2:
|
|
2300
|
+
if (typeof options === 'function') {
|
|
2301
|
+
callback = options;
|
|
2302
|
+
options = {};
|
|
2303
|
+
}
|
|
2304
|
+
break;
|
|
2305
|
+
case 1:
|
|
2306
|
+
if (typeof conditions === 'function') {
|
|
2307
|
+
callback = conditions;
|
|
2308
|
+
conditions = undefined;
|
|
2309
|
+
options = undefined;
|
|
2310
|
+
}
|
|
2311
|
+
break;
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
if (mquery.canMerge(conditions)) {
|
|
2315
|
+
this.merge(conditions);
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
options && this.setOptions(options);
|
|
2319
|
+
|
|
2320
|
+
if (!callback) {
|
|
2321
|
+
return this;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
this._findOneAndDelete(callback);
|
|
2325
|
+
|
|
2326
|
+
return this;
|
|
2327
|
+
};
|
|
2328
|
+
|
|
2329
|
+
/*!
|
|
2330
|
+
* Thunk around findOneAndDelete()
|
|
2331
|
+
*
|
|
2332
|
+
* @param {Function} [callback]
|
|
2333
|
+
* @return {Query} this
|
|
2334
|
+
* @api private
|
|
2335
|
+
*/
|
|
2336
|
+
Query.prototype._findOneAndDelete = function(callback) {
|
|
2337
|
+
this._castConditions();
|
|
2338
|
+
|
|
2339
|
+
if (this.error() != null) {
|
|
2340
|
+
callback(this.error());
|
|
2341
|
+
return null;
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
const filter = this._conditions;
|
|
2345
|
+
const options = this._optionsForExec();
|
|
2346
|
+
let fields = null;
|
|
2347
|
+
|
|
2348
|
+
if (this._fields != null) {
|
|
2349
|
+
options.projection = this._castFields(utils.clone(this._fields));
|
|
2350
|
+
fields = options.projection;
|
|
2351
|
+
if (fields instanceof Error) {
|
|
2352
|
+
callback(fields);
|
|
2353
|
+
return null;
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
this._collection.collection.findOneAndDelete(filter, options, (err, res) => {
|
|
2358
|
+
if (err) {
|
|
2359
|
+
return callback(err);
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
const doc = res.value;
|
|
2363
|
+
|
|
2364
|
+
return this._completeOne(doc, res, callback);
|
|
2365
|
+
});
|
|
2366
|
+
};
|
|
2367
|
+
|
|
2250
2368
|
/*!
|
|
2251
2369
|
* Thunk around findOneAndRemove()
|
|
2252
2370
|
*
|
|
@@ -2256,10 +2374,11 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
|
|
|
2256
2374
|
*/
|
|
2257
2375
|
Query.prototype._findOneAndRemove = function(callback) {
|
|
2258
2376
|
if (this.error() != null) {
|
|
2259
|
-
|
|
2377
|
+
callback(this.error());
|
|
2378
|
+
return;
|
|
2260
2379
|
}
|
|
2261
2380
|
|
|
2262
|
-
|
|
2381
|
+
this._findAndModify('remove', callback);
|
|
2263
2382
|
};
|
|
2264
2383
|
|
|
2265
2384
|
/*!
|
|
@@ -2346,7 +2465,6 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
2346
2465
|
}
|
|
2347
2466
|
|
|
2348
2467
|
this._applyPaths();
|
|
2349
|
-
var userProvidedFields = this._userProvidedFields || {};
|
|
2350
2468
|
|
|
2351
2469
|
var options = this._mongooseOptions;
|
|
2352
2470
|
|
|
@@ -2365,32 +2483,7 @@ Query.prototype._findAndModify = function(type, callback) {
|
|
|
2365
2483
|
return callback(err);
|
|
2366
2484
|
}
|
|
2367
2485
|
|
|
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
|
-
});
|
|
2486
|
+
_this._completeOne(doc, res, callback);
|
|
2394
2487
|
};
|
|
2395
2488
|
|
|
2396
2489
|
var _callback;
|
|
@@ -2550,7 +2643,7 @@ function _updateThunk(op, callback) {
|
|
|
2550
2643
|
|
|
2551
2644
|
if (this.error() != null) {
|
|
2552
2645
|
callback(this.error());
|
|
2553
|
-
return
|
|
2646
|
+
return null;
|
|
2554
2647
|
}
|
|
2555
2648
|
|
|
2556
2649
|
var castedQuery = this._conditions;
|
|
@@ -2566,12 +2659,12 @@ function _updateThunk(op, callback) {
|
|
|
2566
2659
|
|
|
2567
2660
|
if (castedDoc instanceof Error) {
|
|
2568
2661
|
callback(castedDoc);
|
|
2569
|
-
return
|
|
2662
|
+
return null;
|
|
2570
2663
|
}
|
|
2571
2664
|
|
|
2572
2665
|
if (castedDoc == null || Object.keys(castedDoc).length === 0) {
|
|
2573
2666
|
callback(null, 0);
|
|
2574
|
-
return
|
|
2667
|
+
return null;
|
|
2575
2668
|
}
|
|
2576
2669
|
|
|
2577
2670
|
castedDoc = setDefaultsOnInsert(this._conditions, this.model.schema,
|
|
@@ -2603,7 +2696,7 @@ function _updateThunk(op, callback) {
|
|
|
2603
2696
|
callback(err);
|
|
2604
2697
|
});
|
|
2605
2698
|
}
|
|
2606
|
-
return
|
|
2699
|
+
return null;
|
|
2607
2700
|
}
|
|
2608
2701
|
|
|
2609
2702
|
if (castedDoc.toBSON) {
|
|
@@ -2611,7 +2704,7 @@ function _updateThunk(op, callback) {
|
|
|
2611
2704
|
}
|
|
2612
2705
|
|
|
2613
2706
|
this._collection[op](castedQuery, castedDoc, options, callback);
|
|
2614
|
-
return
|
|
2707
|
+
return null;
|
|
2615
2708
|
}
|
|
2616
2709
|
|
|
2617
2710
|
/*!
|
package/lib/queryhelpers.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
1
2
|
|
|
2
3
|
/*!
|
|
3
4
|
* Module dependencies
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const get = require('lodash.get');
|
|
8
|
+
const isDefiningProjection = require('./services/projection/isDefiningProjection');
|
|
9
|
+
const utils = require('./utils');
|
|
9
10
|
|
|
10
11
|
/*!
|
|
11
12
|
* Prepare a set of path options for query population.
|
|
@@ -16,7 +17,7 @@ var utils = require('./utils');
|
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
exports.preparePopulationOptions = function preparePopulationOptions(query, options) {
|
|
19
|
-
|
|
20
|
+
const pop = utils.object.vals(query.options.populate);
|
|
20
21
|
|
|
21
22
|
// lean options should trickle through all queries
|
|
22
23
|
if (options.lean) {
|
|
@@ -36,7 +37,7 @@ exports.preparePopulationOptions = function preparePopulationOptions(query, opti
|
|
|
36
37
|
*/
|
|
37
38
|
|
|
38
39
|
exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query, options) {
|
|
39
|
-
|
|
40
|
+
const pop = utils.object.vals(query._mongooseOptions.populate);
|
|
40
41
|
|
|
41
42
|
// lean options should trickle through all queries
|
|
42
43
|
if (options.lean) {
|
|
@@ -54,12 +55,12 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
|
|
|
54
55
|
* @param {string} value
|
|
55
56
|
*/
|
|
56
57
|
function getDiscriminatorByValue(model, value) {
|
|
57
|
-
|
|
58
|
+
let discriminator = null;
|
|
58
59
|
if (!model.discriminators) {
|
|
59
60
|
return discriminator;
|
|
60
61
|
}
|
|
61
|
-
for (
|
|
62
|
-
|
|
62
|
+
for (const name in model.discriminators) {
|
|
63
|
+
const it = model.discriminators[name];
|
|
63
64
|
if (
|
|
64
65
|
it.schema &&
|
|
65
66
|
it.schema.discriminatorMapping &&
|
|
@@ -85,37 +86,63 @@ exports.getDiscriminatorByValue = getDiscriminatorByValue;
|
|
|
85
86
|
* @return {Model}
|
|
86
87
|
*/
|
|
87
88
|
exports.createModel = function createModel(model, doc, fields, userProvidedFields) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
const discriminatorMapping = model.schema ?
|
|
90
|
+
model.schema.discriminatorMapping :
|
|
91
|
+
null;
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const key = discriminatorMapping && discriminatorMapping.isRoot ?
|
|
94
|
+
discriminatorMapping.key :
|
|
95
|
+
null;
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
const value = doc[key];
|
|
97
98
|
if (key && value && model.discriminators) {
|
|
98
|
-
|
|
99
|
+
const discriminator = model.discriminators[value] || getDiscriminatorByValue(model, value);
|
|
99
100
|
if (discriminator) {
|
|
100
|
-
|
|
101
|
+
const _fields = utils.clone(userProvidedFields);
|
|
101
102
|
exports.applyPaths(_fields, discriminator.schema);
|
|
102
103
|
return new discriminator(undefined, _fields, true);
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
const skipDefaults = gatherPaths(doc, {}, '');
|
|
108
|
+
return new model(undefined, fields, {
|
|
109
|
+
skipId: true,
|
|
110
|
+
isNew: false,
|
|
111
|
+
skipDefaults: skipDefaults
|
|
112
|
+
});
|
|
107
113
|
};
|
|
108
114
|
|
|
115
|
+
/*!
|
|
116
|
+
*
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
function gatherPaths(obj, map, path) {
|
|
120
|
+
for (const key of Object.keys(obj)) {
|
|
121
|
+
const fullPath = path ? path + '.' + key : key;
|
|
122
|
+
map[fullPath] = true;
|
|
123
|
+
if (obj[key] != null &&
|
|
124
|
+
typeof obj[key] === 'object' &&
|
|
125
|
+
!Array.isArray(obj) &&
|
|
126
|
+
!(obj instanceof Map) &&
|
|
127
|
+
!obj[key]._bsontype &&
|
|
128
|
+
!utils.isMongooseObject(obj[key])) {
|
|
129
|
+
gatherPaths(obj[key], map, fullPath);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return map;
|
|
134
|
+
}
|
|
135
|
+
|
|
109
136
|
/*!
|
|
110
137
|
* ignore
|
|
111
138
|
*/
|
|
112
139
|
|
|
113
140
|
exports.applyPaths = function applyPaths(fields, schema) {
|
|
114
141
|
// determine if query is selecting or excluding fields
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
142
|
+
let exclude;
|
|
143
|
+
let keys;
|
|
144
|
+
let ki;
|
|
145
|
+
let field;
|
|
119
146
|
|
|
120
147
|
if (fields) {
|
|
121
148
|
keys = Object.keys(fields);
|
|
@@ -138,11 +165,11 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
138
165
|
// if selecting, apply default schematype select:true fields
|
|
139
166
|
// if excluding, apply schematype select:false fields
|
|
140
167
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
let selected = [];
|
|
169
|
+
let excluded = [];
|
|
170
|
+
let stack = [];
|
|
144
171
|
|
|
145
|
-
|
|
172
|
+
let analyzePath = function(path, type) {
|
|
146
173
|
if (typeof type.selected !== 'boolean') return;
|
|
147
174
|
|
|
148
175
|
var plusPath = '+' + path;
|
|
@@ -160,8 +187,8 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
160
187
|
}
|
|
161
188
|
|
|
162
189
|
// check for parent exclusions
|
|
163
|
-
|
|
164
|
-
|
|
190
|
+
let pieces = path.split('.');
|
|
191
|
+
let root = pieces[0];
|
|
165
192
|
if (~excluded.indexOf(root)) {
|
|
166
193
|
return;
|
|
167
194
|
}
|
|
@@ -170,10 +197,10 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
170
197
|
// don't explicitly project in the discriminator key because that will
|
|
171
198
|
// project out everything else under the parent path
|
|
172
199
|
if (!exclude && get(type, 'options.$skipDiscriminatorCheck', false)) {
|
|
173
|
-
|
|
174
|
-
for (
|
|
200
|
+
let cur = '';
|
|
201
|
+
for (let i = 0; i < pieces.length; ++i) {
|
|
175
202
|
cur += (cur.length === 0 ? '' : '.') + pieces[i];
|
|
176
|
-
|
|
203
|
+
const projection = get(fields, cur, false);
|
|
177
204
|
if (projection && typeof projection !== 'object') {
|
|
178
205
|
return;
|
|
179
206
|
}
|
|
@@ -208,7 +235,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
|
|
|
208
235
|
|
|
209
236
|
analyzeSchema(schema);
|
|
210
237
|
|
|
211
|
-
|
|
238
|
+
let i;
|
|
212
239
|
switch (exclude) {
|
|
213
240
|
case true:
|
|
214
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
|
*/
|