mongoose 8.1.3 → 8.2.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/dist/browser.umd.js +1 -1
- package/lib/aggregate.js +2 -2
- package/lib/connection.js +22 -0
- package/lib/constants.js +36 -0
- package/lib/document.js +2 -6
- package/lib/helpers/model/applyStaticHooks.js +1 -1
- package/lib/helpers/query/applyGlobalOption.js +9 -9
- package/lib/helpers/query/castFilterPath.js +1 -2
- package/lib/helpers/query/validOps.js +1 -18
- package/lib/model.js +192 -62
- package/lib/query.js +44 -15
- package/lib/schema.js +1 -2
- package/package.json +1 -1
- package/types/connection.d.ts +2 -0
- package/types/index.d.ts +40 -2
- package/types/models.d.ts +9 -1
- package/lib/helpers/query/applyQueryMiddleware.js +0 -54
- package/lib/helpers/query/completeMany.js +0 -36
package/lib/aggregate.js
CHANGED
|
@@ -1019,8 +1019,8 @@ Aggregate.prototype.exec = async function exec() {
|
|
|
1019
1019
|
const model = this._model;
|
|
1020
1020
|
const collection = this._model.collection;
|
|
1021
1021
|
|
|
1022
|
-
applyGlobalMaxTimeMS(this.options, model);
|
|
1023
|
-
applyGlobalDiskUse(this.options, model);
|
|
1022
|
+
applyGlobalMaxTimeMS(this.options, model.db.options, model.base.options);
|
|
1023
|
+
applyGlobalDiskUse(this.options, model.db.options, model.base.options);
|
|
1024
1024
|
|
|
1025
1025
|
if (this.options && this.options.cursor) {
|
|
1026
1026
|
return new AggregationCursor(this);
|
package/lib/connection.js
CHANGED
|
@@ -443,6 +443,28 @@ Connection.prototype.createCollections = async function createCollections(option
|
|
|
443
443
|
return result;
|
|
444
444
|
};
|
|
445
445
|
|
|
446
|
+
/**
|
|
447
|
+
* A convenience wrapper for `connection.client.withSession()`.
|
|
448
|
+
*
|
|
449
|
+
* #### Example:
|
|
450
|
+
*
|
|
451
|
+
* await conn.withSession(async session => {
|
|
452
|
+
* const doc = await TestModel.findOne().session(session);
|
|
453
|
+
* });
|
|
454
|
+
*
|
|
455
|
+
* @method withSession
|
|
456
|
+
* @param {Function} executor called with 1 argument: a `ClientSession` instance
|
|
457
|
+
* @return {Promise} resolves to the return value of the executor function
|
|
458
|
+
* @api public
|
|
459
|
+
*/
|
|
460
|
+
|
|
461
|
+
Connection.prototype.withSession = async function withSession(executor) {
|
|
462
|
+
if (arguments.length === 0) {
|
|
463
|
+
throw new Error('Please provide an executor function');
|
|
464
|
+
}
|
|
465
|
+
return await this.client.withSession(executor);
|
|
466
|
+
};
|
|
467
|
+
|
|
446
468
|
/**
|
|
447
469
|
* _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://www.mongodb.com/docs/manual/release-notes/3.6/#client-sessions)
|
|
448
470
|
* for benefits like causal consistency, [retryable writes](https://www.mongodb.com/docs/manual/core/retryable-writes/),
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* ignore
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const queryOperations = Object.freeze([
|
|
8
|
+
// Read
|
|
9
|
+
'countDocuments',
|
|
10
|
+
'distinct',
|
|
11
|
+
'estimatedDocumentCount',
|
|
12
|
+
'find',
|
|
13
|
+
'findOne',
|
|
14
|
+
// Update
|
|
15
|
+
'findOneAndReplace',
|
|
16
|
+
'findOneAndUpdate',
|
|
17
|
+
'replaceOne',
|
|
18
|
+
'updateMany',
|
|
19
|
+
'updateOne',
|
|
20
|
+
// Delete
|
|
21
|
+
'deleteMany',
|
|
22
|
+
'deleteOne',
|
|
23
|
+
'findOneAndDelete'
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
exports.queryOperations = queryOperations;
|
|
27
|
+
|
|
28
|
+
/*!
|
|
29
|
+
* ignore
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const queryMiddlewareFunctions = queryOperations.concat([
|
|
33
|
+
'validate'
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
exports.queryMiddlewareFunctions = queryMiddlewareFunctions;
|
package/lib/document.js
CHANGED
|
@@ -694,7 +694,6 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
694
694
|
init(this, doc, this._doc, opts);
|
|
695
695
|
|
|
696
696
|
markArraySubdocsPopulated(this, opts.populated);
|
|
697
|
-
|
|
698
697
|
this.$emit('init', this);
|
|
699
698
|
this.constructor.emit('init', this);
|
|
700
699
|
|
|
@@ -703,7 +702,6 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
703
702
|
null;
|
|
704
703
|
|
|
705
704
|
applyDefaults(this, this.$__.selected, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);
|
|
706
|
-
|
|
707
705
|
return this;
|
|
708
706
|
};
|
|
709
707
|
|
|
@@ -746,7 +744,6 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
746
744
|
}
|
|
747
745
|
path = prefix + i;
|
|
748
746
|
schemaType = docSchema.path(path);
|
|
749
|
-
|
|
750
747
|
// Should still work if not a model-level discriminator, but should not be
|
|
751
748
|
// necessary. This is *only* to catch the case where we queried using the
|
|
752
749
|
// base model and the discriminated model has a projection
|
|
@@ -770,15 +767,14 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
770
767
|
}
|
|
771
768
|
} else {
|
|
772
769
|
// Retain order when overwriting defaults
|
|
773
|
-
if (doc.hasOwnProperty(i) && obj[i] !== void 0) {
|
|
770
|
+
if (doc.hasOwnProperty(i) && obj[i] !== void 0 && !opts.hydratedPopulatedDocs) {
|
|
774
771
|
delete doc[i];
|
|
775
772
|
}
|
|
776
773
|
if (obj[i] === null) {
|
|
777
774
|
doc[i] = schemaType._castNullish(null);
|
|
778
775
|
} else if (obj[i] !== undefined) {
|
|
779
776
|
const wasPopulated = obj[i].$__ == null ? null : obj[i].$__.wasPopulated;
|
|
780
|
-
|
|
781
|
-
if (schemaType && !wasPopulated) {
|
|
777
|
+
if ((schemaType && !wasPopulated) && !opts.hydratedPopulatedDocs) {
|
|
782
778
|
try {
|
|
783
779
|
if (opts && opts.setters) {
|
|
784
780
|
// Call applySetters with `init = false` because otherwise setters are a noop
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const middlewareFunctions = require('
|
|
3
|
+
const middlewareFunctions = require('../../constants').queryMiddlewareFunctions;
|
|
4
4
|
const promiseOrCallback = require('../promiseOrCallback');
|
|
5
5
|
|
|
6
6
|
module.exports = function applyStaticHooks(model, hooks, statics) {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const utils = require('../../utils');
|
|
4
4
|
|
|
5
|
-
function applyGlobalMaxTimeMS(options,
|
|
6
|
-
applyGlobalOption(options,
|
|
5
|
+
function applyGlobalMaxTimeMS(options, connectionOptions, baseOptions) {
|
|
6
|
+
applyGlobalOption(options, connectionOptions, baseOptions, 'maxTimeMS');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
function applyGlobalDiskUse(options,
|
|
10
|
-
applyGlobalOption(options,
|
|
9
|
+
function applyGlobalDiskUse(options, connectionOptions, baseOptions) {
|
|
10
|
+
applyGlobalOption(options, connectionOptions, baseOptions, 'allowDiskUse');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
module.exports = {
|
|
@@ -16,14 +16,14 @@ module.exports = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
function applyGlobalOption(options,
|
|
19
|
+
function applyGlobalOption(options, connectionOptions, baseOptions, optionName) {
|
|
20
20
|
if (utils.hasUserDefinedProperty(options, optionName)) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if (utils.hasUserDefinedProperty(
|
|
25
|
-
options[optionName] =
|
|
26
|
-
} else if (utils.hasUserDefinedProperty(
|
|
27
|
-
options[optionName] =
|
|
24
|
+
if (utils.hasUserDefinedProperty(connectionOptions, optionName)) {
|
|
25
|
+
options[optionName] = connectionOptions[optionName];
|
|
26
|
+
} else if (utils.hasUserDefinedProperty(baseOptions, optionName)) {
|
|
27
|
+
options[optionName] = baseOptions[optionName];
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const isOperator = require('./isOperator');
|
|
4
4
|
|
|
5
|
-
module.exports = function castFilterPath(
|
|
6
|
-
const ctx = query;
|
|
5
|
+
module.exports = function castFilterPath(ctx, schematype, val) {
|
|
7
6
|
const any$conditionals = Object.keys(val).some(isOperator);
|
|
8
7
|
|
|
9
8
|
if (!any$conditionals) {
|
|
@@ -1,20 +1,3 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
module.exports =
|
|
4
|
-
// Read
|
|
5
|
-
'countDocuments',
|
|
6
|
-
'distinct',
|
|
7
|
-
'estimatedDocumentCount',
|
|
8
|
-
'find',
|
|
9
|
-
'findOne',
|
|
10
|
-
// Update
|
|
11
|
-
'findOneAndReplace',
|
|
12
|
-
'findOneAndUpdate',
|
|
13
|
-
'replaceOne',
|
|
14
|
-
'updateMany',
|
|
15
|
-
'updateOne',
|
|
16
|
-
// Delete
|
|
17
|
-
'deleteMany',
|
|
18
|
-
'deleteOne',
|
|
19
|
-
'findOneAndDelete'
|
|
20
|
-
]);
|
|
3
|
+
module.exports = require('../../constants').queryMiddlewareFunctions;
|
package/lib/model.js
CHANGED
|
@@ -23,7 +23,6 @@ const VersionError = require('./error/version');
|
|
|
23
23
|
const ParallelSaveError = require('./error/parallelSave');
|
|
24
24
|
const applyDefaultsHelper = require('./helpers/document/applyDefaults');
|
|
25
25
|
const applyDefaultsToPOJO = require('./helpers/model/applyDefaultsToPOJO');
|
|
26
|
-
const applyQueryMiddleware = require('./helpers/query/applyQueryMiddleware');
|
|
27
26
|
const applyHooks = require('./helpers/model/applyHooks');
|
|
28
27
|
const applyMethods = require('./helpers/model/applyMethods');
|
|
29
28
|
const applyProjection = require('./helpers/projection/applyProjection');
|
|
@@ -1415,6 +1414,18 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1415
1414
|
throw new MongooseError('Model.createCollection() no longer accepts a callback');
|
|
1416
1415
|
}
|
|
1417
1416
|
|
|
1417
|
+
const shouldSkip = await new Promise((resolve, reject) => {
|
|
1418
|
+
this.hooks.execPre('createCollection', this, [options], (err) => {
|
|
1419
|
+
if (err != null) {
|
|
1420
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
1421
|
+
return resolve(true);
|
|
1422
|
+
}
|
|
1423
|
+
return reject(err);
|
|
1424
|
+
}
|
|
1425
|
+
resolve();
|
|
1426
|
+
});
|
|
1427
|
+
});
|
|
1428
|
+
|
|
1418
1429
|
const collectionOptions = this &&
|
|
1419
1430
|
this.schema &&
|
|
1420
1431
|
this.schema.options &&
|
|
@@ -1468,13 +1479,32 @@ Model.createCollection = async function createCollection(options) {
|
|
|
1468
1479
|
}
|
|
1469
1480
|
|
|
1470
1481
|
try {
|
|
1471
|
-
|
|
1482
|
+
if (!shouldSkip) {
|
|
1483
|
+
await this.db.createCollection(this.$__collection.collectionName, options);
|
|
1484
|
+
}
|
|
1472
1485
|
} catch (err) {
|
|
1473
|
-
|
|
1474
1486
|
if (err != null && (err.name !== 'MongoServerError' || err.code !== 48)) {
|
|
1475
|
-
|
|
1487
|
+
await new Promise((resolve, reject) => {
|
|
1488
|
+
const _opts = { error: err };
|
|
1489
|
+
this.hooks.execPost('createCollection', this, [null], _opts, (err) => {
|
|
1490
|
+
if (err != null) {
|
|
1491
|
+
return reject(err);
|
|
1492
|
+
}
|
|
1493
|
+
resolve();
|
|
1494
|
+
});
|
|
1495
|
+
});
|
|
1476
1496
|
}
|
|
1477
1497
|
}
|
|
1498
|
+
|
|
1499
|
+
await new Promise((resolve, reject) => {
|
|
1500
|
+
this.hooks.execPost('createCollection', this, [this.$__collection], (err) => {
|
|
1501
|
+
if (err != null) {
|
|
1502
|
+
return reject(err);
|
|
1503
|
+
}
|
|
1504
|
+
resolve();
|
|
1505
|
+
});
|
|
1506
|
+
});
|
|
1507
|
+
|
|
1478
1508
|
return this.$__collection;
|
|
1479
1509
|
};
|
|
1480
1510
|
|
|
@@ -3428,44 +3458,62 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3428
3458
|
throw new MongooseError('Model.bulkWrite() no longer accepts a callback');
|
|
3429
3459
|
}
|
|
3430
3460
|
options = options || {};
|
|
3461
|
+
|
|
3462
|
+
const shouldSkip = await new Promise((resolve, reject) => {
|
|
3463
|
+
this.hooks.execPre('bulkWrite', this, [ops, options], (err) => {
|
|
3464
|
+
if (err != null) {
|
|
3465
|
+
if (err instanceof Kareem.skipWrappedFunction) {
|
|
3466
|
+
return resolve(err);
|
|
3467
|
+
}
|
|
3468
|
+
return reject(err);
|
|
3469
|
+
}
|
|
3470
|
+
resolve();
|
|
3471
|
+
});
|
|
3472
|
+
});
|
|
3473
|
+
|
|
3474
|
+
if (shouldSkip) {
|
|
3475
|
+
return shouldSkip.args[0];
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3431
3478
|
const ordered = options.ordered == null ? true : options.ordered;
|
|
3432
3479
|
|
|
3480
|
+
if (ops.length === 0) {
|
|
3481
|
+
return getDefaultBulkwriteResult();
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3433
3484
|
const validations = ops.map(op => castBulkWrite(this, op, options));
|
|
3434
3485
|
|
|
3435
|
-
|
|
3436
|
-
|
|
3486
|
+
let res = null;
|
|
3487
|
+
if (ordered) {
|
|
3488
|
+
await new Promise((resolve, reject) => {
|
|
3437
3489
|
each(validations, (fn, cb) => fn(cb), error => {
|
|
3438
3490
|
if (error) {
|
|
3439
3491
|
return reject(error);
|
|
3440
3492
|
}
|
|
3441
3493
|
|
|
3442
|
-
|
|
3443
|
-
return resolve(getDefaultBulkwriteResult());
|
|
3444
|
-
}
|
|
3445
|
-
|
|
3446
|
-
try {
|
|
3447
|
-
this.$__collection.bulkWrite(ops, options, (error, res) => {
|
|
3448
|
-
if (error) {
|
|
3449
|
-
return reject(error);
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
|
-
resolve(res);
|
|
3453
|
-
});
|
|
3454
|
-
} catch (err) {
|
|
3455
|
-
return reject(err);
|
|
3456
|
-
}
|
|
3494
|
+
resolve();
|
|
3457
3495
|
});
|
|
3496
|
+
});
|
|
3458
3497
|
|
|
3459
|
-
|
|
3498
|
+
try {
|
|
3499
|
+
res = await this.$__collection.bulkWrite(ops, options);
|
|
3500
|
+
} catch (error) {
|
|
3501
|
+
await new Promise((resolve, reject) => {
|
|
3502
|
+
const _opts = { error: error };
|
|
3503
|
+
this.hooks.execPost('bulkWrite', this, [null], _opts, (err) => {
|
|
3504
|
+
if (err != null) {
|
|
3505
|
+
return reject(err);
|
|
3506
|
+
}
|
|
3507
|
+
resolve();
|
|
3508
|
+
});
|
|
3509
|
+
});
|
|
3460
3510
|
}
|
|
3461
|
-
|
|
3511
|
+
} else {
|
|
3462
3512
|
let remaining = validations.length;
|
|
3463
3513
|
let validOps = [];
|
|
3464
3514
|
let validationErrors = [];
|
|
3465
3515
|
const results = [];
|
|
3466
|
-
|
|
3467
|
-
completeUnorderedValidation.call(this);
|
|
3468
|
-
} else {
|
|
3516
|
+
await new Promise((resolve) => {
|
|
3469
3517
|
for (let i = 0; i < validations.length; ++i) {
|
|
3470
3518
|
validations[i]((err) => {
|
|
3471
3519
|
if (err == null) {
|
|
@@ -3475,56 +3523,74 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3475
3523
|
results[i] = err;
|
|
3476
3524
|
}
|
|
3477
3525
|
if (--remaining <= 0) {
|
|
3478
|
-
|
|
3526
|
+
resolve();
|
|
3479
3527
|
}
|
|
3480
3528
|
});
|
|
3481
3529
|
}
|
|
3482
|
-
}
|
|
3530
|
+
});
|
|
3483
3531
|
|
|
3484
3532
|
validationErrors = validationErrors.
|
|
3485
3533
|
sort((v1, v2) => v1.index - v2.index).
|
|
3486
3534
|
map(v => v.error);
|
|
3487
3535
|
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
validOps = validOps.sort().map(index => ops[index]);
|
|
3536
|
+
const validOpIndexes = validOps;
|
|
3537
|
+
validOps = validOps.sort().map(index => ops[index]);
|
|
3491
3538
|
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3539
|
+
if (validOps.length === 0) {
|
|
3540
|
+
return getDefaultBulkwriteResult();
|
|
3541
|
+
}
|
|
3495
3542
|
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
error.mongoose.validationErrors = validationErrors;
|
|
3501
|
-
}
|
|
3543
|
+
let error;
|
|
3544
|
+
[res, error] = await this.$__collection.bulkWrite(validOps, options).
|
|
3545
|
+
then(res => ([res, null])).
|
|
3546
|
+
catch(err => ([null, err]));
|
|
3502
3547
|
|
|
3503
|
-
|
|
3504
|
-
|
|
3548
|
+
if (error) {
|
|
3549
|
+
if (validationErrors.length > 0) {
|
|
3550
|
+
error.mongoose = error.mongoose || {};
|
|
3551
|
+
error.mongoose.validationErrors = validationErrors;
|
|
3552
|
+
}
|
|
3505
3553
|
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
return reject(new MongooseBulkWriteError(
|
|
3512
|
-
validationErrors,
|
|
3513
|
-
results,
|
|
3514
|
-
res,
|
|
3515
|
-
'bulkWrite'
|
|
3516
|
-
));
|
|
3517
|
-
} else {
|
|
3518
|
-
res.mongoose = res.mongoose || {};
|
|
3519
|
-
res.mongoose.validationErrors = validationErrors;
|
|
3520
|
-
res.mongoose.results = results;
|
|
3554
|
+
await new Promise((resolve, reject) => {
|
|
3555
|
+
const _opts = { error: error };
|
|
3556
|
+
this.hooks.execPost('bulkWrite', this, [null], _opts, (err) => {
|
|
3557
|
+
if (err != null) {
|
|
3558
|
+
return reject(err);
|
|
3521
3559
|
}
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
resolve(res);
|
|
3560
|
+
resolve();
|
|
3561
|
+
});
|
|
3525
3562
|
});
|
|
3526
3563
|
}
|
|
3564
|
+
|
|
3565
|
+
for (let i = 0; i < validOpIndexes.length; ++i) {
|
|
3566
|
+
results[validOpIndexes[i]] = null;
|
|
3567
|
+
}
|
|
3568
|
+
if (validationErrors.length > 0) {
|
|
3569
|
+
if (options.throwOnValidationError) {
|
|
3570
|
+
throw new MongooseBulkWriteError(
|
|
3571
|
+
validationErrors,
|
|
3572
|
+
results,
|
|
3573
|
+
res,
|
|
3574
|
+
'bulkWrite'
|
|
3575
|
+
);
|
|
3576
|
+
} else {
|
|
3577
|
+
res.mongoose = res.mongoose || {};
|
|
3578
|
+
res.mongoose.validationErrors = validationErrors;
|
|
3579
|
+
res.mongoose.results = results;
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
await new Promise((resolve, reject) => {
|
|
3585
|
+
this.hooks.execPost('bulkWrite', this, [res], (err) => {
|
|
3586
|
+
if (err != null) {
|
|
3587
|
+
return reject(err);
|
|
3588
|
+
}
|
|
3589
|
+
resolve();
|
|
3590
|
+
});
|
|
3527
3591
|
});
|
|
3592
|
+
|
|
3593
|
+
return res;
|
|
3528
3594
|
};
|
|
3529
3595
|
|
|
3530
3596
|
/**
|
|
@@ -3830,6 +3896,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
|
|
|
3830
3896
|
* @param {Object|String|String[]} [projection] optional projection containing which fields should be selected for this document
|
|
3831
3897
|
* @param {Object} [options] optional options
|
|
3832
3898
|
* @param {Boolean} [options.setters=false] if true, apply schema setters when hydrating
|
|
3899
|
+
* @param {Boolean} [options.hydratedPopulatedDocs=false] if true, populates the docs if passing pre-populated data
|
|
3833
3900
|
* @return {Document} document instance
|
|
3834
3901
|
* @api public
|
|
3835
3902
|
*/
|
|
@@ -3843,7 +3910,6 @@ Model.hydrate = function(obj, projection, options) {
|
|
|
3843
3910
|
}
|
|
3844
3911
|
obj = applyProjection(obj, projection);
|
|
3845
3912
|
}
|
|
3846
|
-
|
|
3847
3913
|
const document = require('./queryHelpers').createModel(this, obj, projection);
|
|
3848
3914
|
document.$init(obj, options);
|
|
3849
3915
|
return document;
|
|
@@ -4774,7 +4840,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
|
|
|
4774
4840
|
Object.setPrototypeOf(model.Query.prototype, Query.prototype);
|
|
4775
4841
|
model.Query.base = Query.base;
|
|
4776
4842
|
model.Query.prototype.constructor = Query;
|
|
4777
|
-
|
|
4843
|
+
model._applyQueryMiddleware();
|
|
4778
4844
|
applyQueryMethods(model, schema.query);
|
|
4779
4845
|
|
|
4780
4846
|
return model;
|
|
@@ -4861,6 +4927,35 @@ Model.__subclass = function subclass(conn, schema, collection) {
|
|
|
4861
4927
|
return Model;
|
|
4862
4928
|
};
|
|
4863
4929
|
|
|
4930
|
+
/**
|
|
4931
|
+
* Apply changes made to this model's schema after this model was compiled.
|
|
4932
|
+
* By default, adding virtuals and other properties to a schema after the model is compiled does nothing.
|
|
4933
|
+
* Call this function to apply virtuals and properties that were added later.
|
|
4934
|
+
*
|
|
4935
|
+
* #### Example:
|
|
4936
|
+
*
|
|
4937
|
+
* const schema = new mongoose.Schema({ field: String });
|
|
4938
|
+
* const TestModel = mongoose.model('Test', schema);
|
|
4939
|
+
* TestModel.schema.virtual('myVirtual').get(function() {
|
|
4940
|
+
* return this.field + ' from myVirtual';
|
|
4941
|
+
* });
|
|
4942
|
+
* const doc = new TestModel({ field: 'Hello' });
|
|
4943
|
+
* doc.myVirtual; // undefined
|
|
4944
|
+
*
|
|
4945
|
+
* TestModel.recompileSchema();
|
|
4946
|
+
* doc.myVirtual; // 'Hello from myVirtual'
|
|
4947
|
+
*
|
|
4948
|
+
* @return {undefined}
|
|
4949
|
+
* @api public
|
|
4950
|
+
* @memberOf Model
|
|
4951
|
+
* @static
|
|
4952
|
+
* @method recompileSchema
|
|
4953
|
+
*/
|
|
4954
|
+
|
|
4955
|
+
Model.recompileSchema = function recompileSchema() {
|
|
4956
|
+
this.prototype.$__setSchema(this.schema);
|
|
4957
|
+
};
|
|
4958
|
+
|
|
4864
4959
|
/**
|
|
4865
4960
|
* Helper for console.log. Given a model named 'MyModel', returns the string
|
|
4866
4961
|
* `'Model { MyModel }'`.
|
|
@@ -4883,6 +4978,41 @@ if (util.inspect.custom) {
|
|
|
4883
4978
|
Model[util.inspect.custom] = Model.inspect;
|
|
4884
4979
|
}
|
|
4885
4980
|
|
|
4981
|
+
/*!
|
|
4982
|
+
* Applies query middleware from this model's schema to this model's
|
|
4983
|
+
* Query constructor.
|
|
4984
|
+
*/
|
|
4985
|
+
|
|
4986
|
+
Model._applyQueryMiddleware = function _applyQueryMiddleware() {
|
|
4987
|
+
const Query = this.Query;
|
|
4988
|
+
const queryMiddleware = this.schema.s.hooks.filter(hook => {
|
|
4989
|
+
const contexts = _getContexts(hook);
|
|
4990
|
+
if (hook.name === 'validate') {
|
|
4991
|
+
return !!contexts.query;
|
|
4992
|
+
}
|
|
4993
|
+
if (hook.name === 'deleteOne' || hook.name === 'updateOne') {
|
|
4994
|
+
return !!contexts.query || Object.keys(contexts).length === 0;
|
|
4995
|
+
}
|
|
4996
|
+
if (hook.query != null || hook.document != null) {
|
|
4997
|
+
return !!hook.query;
|
|
4998
|
+
}
|
|
4999
|
+
return true;
|
|
5000
|
+
});
|
|
5001
|
+
|
|
5002
|
+
Query.prototype._queryMiddleware = queryMiddleware;
|
|
5003
|
+
};
|
|
5004
|
+
|
|
5005
|
+
function _getContexts(hook) {
|
|
5006
|
+
const ret = {};
|
|
5007
|
+
if (hook.hasOwnProperty('query')) {
|
|
5008
|
+
ret.query = hook.query;
|
|
5009
|
+
}
|
|
5010
|
+
if (hook.hasOwnProperty('document')) {
|
|
5011
|
+
ret.document = hook.document;
|
|
5012
|
+
}
|
|
5013
|
+
return ret;
|
|
5014
|
+
}
|
|
5015
|
+
|
|
4886
5016
|
/*!
|
|
4887
5017
|
* Module exports.
|
|
4888
5018
|
*/
|
package/lib/query.js
CHANGED
|
@@ -19,7 +19,6 @@ const castArrayFilters = require('./helpers/update/castArrayFilters');
|
|
|
19
19
|
const castNumber = require('./cast/number');
|
|
20
20
|
const castUpdate = require('./helpers/query/castUpdate');
|
|
21
21
|
const clone = require('./helpers/clone');
|
|
22
|
-
const completeMany = require('./helpers/query/completeMany');
|
|
23
22
|
const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
|
|
24
23
|
const helpers = require('./queryHelpers');
|
|
25
24
|
const immediate = require('./helpers/immediate');
|
|
@@ -40,7 +39,7 @@ const specialProperties = require('./helpers/specialProperties');
|
|
|
40
39
|
const updateValidators = require('./helpers/updateValidators');
|
|
41
40
|
const util = require('util');
|
|
42
41
|
const utils = require('./utils');
|
|
43
|
-
const
|
|
42
|
+
const queryMiddlewareFunctions = require('./constants').queryMiddlewareFunctions;
|
|
44
43
|
|
|
45
44
|
const queryOptionMethods = new Set([
|
|
46
45
|
'allowDiskUse',
|
|
@@ -457,7 +456,7 @@ Query.prototype.slice = function() {
|
|
|
457
456
|
* ignore
|
|
458
457
|
*/
|
|
459
458
|
|
|
460
|
-
const validOpsSet = new Set(
|
|
459
|
+
const validOpsSet = new Set(queryMiddlewareFunctions);
|
|
461
460
|
|
|
462
461
|
Query.prototype._validateOp = function() {
|
|
463
462
|
if (this.op != null && !validOpsSet.has(this.op)) {
|
|
@@ -2233,8 +2232,8 @@ Query.prototype._find = async function _find() {
|
|
|
2233
2232
|
const _this = this;
|
|
2234
2233
|
const userProvidedFields = _this._userProvidedFields || {};
|
|
2235
2234
|
|
|
2236
|
-
applyGlobalMaxTimeMS(this.options, this.model);
|
|
2237
|
-
applyGlobalDiskUse(this.options, this.model);
|
|
2235
|
+
applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
|
|
2236
|
+
applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
|
|
2238
2237
|
|
|
2239
2238
|
// Separate options to pass down to `completeMany()` in case we need to
|
|
2240
2239
|
// set a session on the document
|
|
@@ -2271,7 +2270,7 @@ Query.prototype._find = async function _find() {
|
|
|
2271
2270
|
}
|
|
2272
2271
|
return mongooseOptions.lean ?
|
|
2273
2272
|
_completeManyLean(_this.model.schema, docs, null, completeManyOptions) :
|
|
2274
|
-
|
|
2273
|
+
_this._completeMany(docs, fields, userProvidedFields, completeManyOptions);
|
|
2275
2274
|
}
|
|
2276
2275
|
const pop = helpers.preparePopulationOptionsMQ(_this, mongooseOptions);
|
|
2277
2276
|
|
|
@@ -2279,7 +2278,7 @@ Query.prototype._find = async function _find() {
|
|
|
2279
2278
|
return _this.model.populate(docs, pop);
|
|
2280
2279
|
}
|
|
2281
2280
|
|
|
2282
|
-
docs = await
|
|
2281
|
+
docs = await _this._completeMany(docs, fields, userProvidedFields, completeManyOptions);
|
|
2283
2282
|
await this.model.populate(docs, pop);
|
|
2284
2283
|
|
|
2285
2284
|
return docs;
|
|
@@ -2473,6 +2472,36 @@ Query.prototype._completeOne = function(doc, res, callback) {
|
|
|
2473
2472
|
});
|
|
2474
2473
|
};
|
|
2475
2474
|
|
|
2475
|
+
/**
|
|
2476
|
+
* Given a model and an array of docs, hydrates all the docs to be instances
|
|
2477
|
+
* of the model. Used to initialize docs returned from the db from `find()`
|
|
2478
|
+
*
|
|
2479
|
+
* @param {Array} docs
|
|
2480
|
+
* @param {Object} fields the projection used, including `select` from schemas
|
|
2481
|
+
* @param {Object} userProvidedFields the user-specified projection
|
|
2482
|
+
* @param {Object} [opts]
|
|
2483
|
+
* @param {Array} [opts.populated]
|
|
2484
|
+
* @param {ClientSession} [opts.session]
|
|
2485
|
+
* @api private
|
|
2486
|
+
*/
|
|
2487
|
+
|
|
2488
|
+
Query.prototype._completeMany = async function _completeMany(docs, fields, userProvidedFields, opts) {
|
|
2489
|
+
const model = this.model;
|
|
2490
|
+
return Promise.all(docs.map(doc => new Promise((resolve, reject) => {
|
|
2491
|
+
const rawDoc = doc;
|
|
2492
|
+
doc = helpers.createModel(model, doc, fields, userProvidedFields);
|
|
2493
|
+
if (opts.session != null) {
|
|
2494
|
+
doc.$session(opts.session);
|
|
2495
|
+
}
|
|
2496
|
+
doc.$init(rawDoc, opts, (err) => {
|
|
2497
|
+
if (err != null) {
|
|
2498
|
+
return reject(err);
|
|
2499
|
+
}
|
|
2500
|
+
resolve(doc);
|
|
2501
|
+
});
|
|
2502
|
+
})));
|
|
2503
|
+
};
|
|
2504
|
+
|
|
2476
2505
|
/**
|
|
2477
2506
|
* Internal helper to execute a findOne() operation
|
|
2478
2507
|
*
|
|
@@ -2488,8 +2517,8 @@ Query.prototype._findOne = async function _findOne() {
|
|
|
2488
2517
|
throw err;
|
|
2489
2518
|
}
|
|
2490
2519
|
|
|
2491
|
-
applyGlobalMaxTimeMS(this.options, this.model);
|
|
2492
|
-
applyGlobalDiskUse(this.options, this.model);
|
|
2520
|
+
applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
|
|
2521
|
+
applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
|
|
2493
2522
|
|
|
2494
2523
|
const options = this._optionsForExec();
|
|
2495
2524
|
|
|
@@ -2585,8 +2614,8 @@ Query.prototype._countDocuments = async function _countDocuments() {
|
|
|
2585
2614
|
throw this.error();
|
|
2586
2615
|
}
|
|
2587
2616
|
|
|
2588
|
-
applyGlobalMaxTimeMS(this.options, this.model);
|
|
2589
|
-
applyGlobalDiskUse(this.options, this.model);
|
|
2617
|
+
applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
|
|
2618
|
+
applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
|
|
2590
2619
|
|
|
2591
2620
|
const options = this._optionsForExec();
|
|
2592
2621
|
|
|
@@ -2754,8 +2783,8 @@ Query.prototype.__distinct = async function __distinct() {
|
|
|
2754
2783
|
throw this.error();
|
|
2755
2784
|
}
|
|
2756
2785
|
|
|
2757
|
-
applyGlobalMaxTimeMS(this.options, this.model);
|
|
2758
|
-
applyGlobalDiskUse(this.options, this.model);
|
|
2786
|
+
applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
|
|
2787
|
+
applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
|
|
2759
2788
|
|
|
2760
2789
|
const options = this._optionsForExec();
|
|
2761
2790
|
this._applyTranslateAliases(options);
|
|
@@ -3247,8 +3276,8 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
|
|
|
3247
3276
|
throw this.error();
|
|
3248
3277
|
}
|
|
3249
3278
|
|
|
3250
|
-
applyGlobalMaxTimeMS(this.options, this.model);
|
|
3251
|
-
applyGlobalDiskUse(this.options, this.model);
|
|
3279
|
+
applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
|
|
3280
|
+
applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
|
|
3252
3281
|
|
|
3253
3282
|
if ('strict' in this.options) {
|
|
3254
3283
|
this._mongooseOptions.strict = this.options.strict;
|