mongoose 8.1.2 → 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/cursor/aggregationCursor.js +8 -0
- package/lib/document.js +17 -11
- package/lib/helpers/model/applyStaticHooks.js +1 -1
- package/lib/helpers/populate/getModelsMapForPopulate.js +2 -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/options.js +2 -1
- package/lib/plugins/trackTransaction.js +1 -1
- 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;
|
|
@@ -57,12 +57,20 @@ util.inherits(AggregationCursor, Readable);
|
|
|
57
57
|
function _init(model, c, agg) {
|
|
58
58
|
if (!model.collection.buffer) {
|
|
59
59
|
model.hooks.execPre('aggregate', agg, function() {
|
|
60
|
+
if (typeof agg.options?.cursor?.transform === 'function') {
|
|
61
|
+
c._transforms.push(agg.options.cursor.transform);
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
|
|
61
65
|
c.emit('cursor', c.cursor);
|
|
62
66
|
});
|
|
63
67
|
} else {
|
|
64
68
|
model.collection.emitter.once('queue', function() {
|
|
65
69
|
model.hooks.execPre('aggregate', agg, function() {
|
|
70
|
+
if (typeof agg.options?.cursor?.transform === 'function') {
|
|
71
|
+
c._transforms.push(agg.options.cursor.transform);
|
|
72
|
+
}
|
|
73
|
+
|
|
66
74
|
c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
|
|
67
75
|
c.emit('cursor', c.cursor);
|
|
68
76
|
});
|
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
|
|
@@ -3901,14 +3897,24 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3901
3897
|
*
|
|
3902
3898
|
* _Note: if a transform function returns `undefined`, the return value will be ignored._
|
|
3903
3899
|
*
|
|
3904
|
-
* Transformations may also be applied inline, overridding any transform set in the options
|
|
3900
|
+
* Transformations may also be applied inline, overridding any transform set in the schema options.
|
|
3901
|
+
* Any transform function specified in `toObject` options also propagates to any subdocuments.
|
|
3905
3902
|
*
|
|
3906
|
-
* function
|
|
3907
|
-
*
|
|
3903
|
+
* function deleteId(doc, ret, options) {
|
|
3904
|
+
* delete ret._id;
|
|
3905
|
+
* return ret;
|
|
3908
3906
|
* }
|
|
3909
3907
|
*
|
|
3910
|
-
*
|
|
3911
|
-
*
|
|
3908
|
+
* const schema = mongoose.Schema({ name: String, docArr: [{ name: String }] });
|
|
3909
|
+
* const TestModel = mongoose.model('Test', schema);
|
|
3910
|
+
*
|
|
3911
|
+
* const doc = new TestModel({ name: 'test', docArr: [{ name: 'test' }] });
|
|
3912
|
+
*
|
|
3913
|
+
* // pass the transform as an inline option. Deletes `_id` property
|
|
3914
|
+
* // from both the top-level document and the subdocument.
|
|
3915
|
+
* const obj = doc.toObject({ transform: deleteId });
|
|
3916
|
+
* obj._id; // undefined
|
|
3917
|
+
* obj.docArr[0]._id; // undefined
|
|
3912
3918
|
*
|
|
3913
3919
|
* If you want to skip transformations, use `transform: false`:
|
|
3914
3920
|
*
|
|
@@ -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) {
|
|
@@ -494,7 +494,7 @@ function addModelNamesToMap(model, map, available, modelNames, options, data, re
|
|
|
494
494
|
|
|
495
495
|
let k = modelNames.length;
|
|
496
496
|
while (k--) {
|
|
497
|
-
|
|
497
|
+
let modelName = modelNames[k];
|
|
498
498
|
if (modelName == null) {
|
|
499
499
|
continue;
|
|
500
500
|
}
|
|
@@ -504,6 +504,7 @@ function addModelNamesToMap(model, map, available, modelNames, options, data, re
|
|
|
504
504
|
Model = options.model;
|
|
505
505
|
} else if (modelName[modelSymbol]) {
|
|
506
506
|
Model = modelName;
|
|
507
|
+
modelName = Model.modelName;
|
|
507
508
|
} else {
|
|
508
509
|
try {
|
|
509
510
|
Model = _getModelFromConn(connection, modelName);
|
|
@@ -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/options.js
CHANGED
|
@@ -85,7 +85,7 @@ function mergeAtomics(destination, source) {
|
|
|
85
85
|
destination.$addToSet = (destination.$addToSet || []).concat(source.$addToSet);
|
|
86
86
|
}
|
|
87
87
|
if (source.$set != null) {
|
|
88
|
-
destination.$set =
|
|
88
|
+
destination.$set = Array.isArray(source.$set) ? [...source.$set] : Object.assign({}, source.$set);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
return destination;
|