mongoose 8.10.1 → 8.11.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/cast/bigint.js +13 -3
- package/lib/connection.js +9 -7
- package/lib/document.js +37 -6
- package/lib/drivers/browser/index.js +1 -0
- package/lib/drivers/node-mongodb-native/bulkWriteResult.js +5 -0
- package/lib/drivers/node-mongodb-native/collection.js +5 -1
- package/lib/drivers/node-mongodb-native/index.js +1 -0
- package/lib/helpers/clone.js +1 -1
- package/lib/helpers/getDefaultBulkwriteResult.js +11 -20
- package/lib/helpers/model/decorateBulkWriteResult.js +8 -0
- package/lib/model.js +57 -36
- package/lib/types/double.js +13 -0
- package/lib/types/index.js +1 -0
- package/lib/utils.js +7 -3
- package/package.json +1 -1
- package/types/index.d.ts +54 -46
- package/types/inferschematype.d.ts +19 -14
- package/types/models.d.ts +1 -1
- package/types/populate.d.ts +6 -0
- package/types/types.d.ts +2 -0
package/lib/cast/bigint.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const assert = require('assert');
|
|
4
3
|
const { Long } = require('bson');
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -13,6 +12,10 @@ const { Long } = require('bson');
|
|
|
13
12
|
* @api private
|
|
14
13
|
*/
|
|
15
14
|
|
|
15
|
+
const MAX_BIGINT = 9223372036854775807n;
|
|
16
|
+
const MIN_BIGINT = -9223372036854775808n;
|
|
17
|
+
const ERROR_MESSAGE = `Mongoose only supports BigInts between ${MIN_BIGINT} and ${MAX_BIGINT} because MongoDB does not support arbitrary precision integers`;
|
|
18
|
+
|
|
16
19
|
module.exports = function castBigInt(val) {
|
|
17
20
|
if (val == null) {
|
|
18
21
|
return val;
|
|
@@ -21,6 +24,9 @@ module.exports = function castBigInt(val) {
|
|
|
21
24
|
return null;
|
|
22
25
|
}
|
|
23
26
|
if (typeof val === 'bigint') {
|
|
27
|
+
if (val > MAX_BIGINT || val < MIN_BIGINT) {
|
|
28
|
+
throw new Error(ERROR_MESSAGE);
|
|
29
|
+
}
|
|
24
30
|
return val;
|
|
25
31
|
}
|
|
26
32
|
|
|
@@ -29,8 +35,12 @@ module.exports = function castBigInt(val) {
|
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
if (typeof val === 'string' || typeof val === 'number') {
|
|
32
|
-
|
|
38
|
+
val = BigInt(val);
|
|
39
|
+
if (val > MAX_BIGINT || val < MIN_BIGINT) {
|
|
40
|
+
throw new Error(ERROR_MESSAGE);
|
|
41
|
+
}
|
|
42
|
+
return val;
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
throw new Error(`Cannot convert value to BigInt: "${val}"`);
|
|
36
46
|
};
|
package/lib/connection.js
CHANGED
|
@@ -23,6 +23,7 @@ const CreateCollectionsError = require('./error/createCollectionsError');
|
|
|
23
23
|
const castBulkWrite = require('./helpers/model/castBulkWrite');
|
|
24
24
|
const { modelSymbol } = require('./helpers/symbols');
|
|
25
25
|
const isPromise = require('./helpers/isPromise');
|
|
26
|
+
const decorateBulkWriteResult = require('./helpers/model/decorateBulkWriteResult');
|
|
26
27
|
|
|
27
28
|
const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
|
|
28
29
|
const sessionNewDocuments = require('./helpers/symbols').sessionNewDocuments;
|
|
@@ -559,7 +560,9 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
559
560
|
'bulkWrite'
|
|
560
561
|
);
|
|
561
562
|
}
|
|
562
|
-
|
|
563
|
+
const BulkWriteResult = this.base.driver.get().BulkWriteResult;
|
|
564
|
+
const res = new BulkWriteResult(getDefaultBulkwriteResult(), false);
|
|
565
|
+
return decorateBulkWriteResult(res, validationErrors, results);
|
|
563
566
|
}
|
|
564
567
|
|
|
565
568
|
let error;
|
|
@@ -567,16 +570,17 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
567
570
|
then(res => ([res, null])).
|
|
568
571
|
catch(err => ([null, err]));
|
|
569
572
|
|
|
573
|
+
for (let i = 0; i < validOpIndexes.length; ++i) {
|
|
574
|
+
results[validOpIndexes[i]] = null;
|
|
575
|
+
}
|
|
570
576
|
if (error) {
|
|
571
577
|
if (validationErrors.length > 0) {
|
|
578
|
+
decorateBulkWriteResult(error, validationErrors, results);
|
|
572
579
|
error.mongoose = error.mongoose || {};
|
|
573
580
|
error.mongoose.validationErrors = validationErrors;
|
|
574
581
|
}
|
|
575
582
|
}
|
|
576
583
|
|
|
577
|
-
for (let i = 0; i < validOpIndexes.length; ++i) {
|
|
578
|
-
results[validOpIndexes[i]] = null;
|
|
579
|
-
}
|
|
580
584
|
if (validationErrors.length > 0) {
|
|
581
585
|
if (options.throwOnValidationError) {
|
|
582
586
|
throw new MongooseBulkWriteError(
|
|
@@ -586,9 +590,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
586
590
|
'bulkWrite'
|
|
587
591
|
);
|
|
588
592
|
} else {
|
|
589
|
-
res
|
|
590
|
-
res.mongoose.validationErrors = validationErrors;
|
|
591
|
-
res.mongoose.results = results;
|
|
593
|
+
decorateBulkWriteResult(res, validationErrors, results);
|
|
592
594
|
}
|
|
593
595
|
}
|
|
594
596
|
}
|
package/lib/document.js
CHANGED
|
@@ -3836,15 +3836,39 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3836
3836
|
// Parent options should only bubble down for subdocuments, not populated docs
|
|
3837
3837
|
options._parentOptions = this.$isSubdocument ? options : null;
|
|
3838
3838
|
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3839
|
+
const schemaFieldsOnly = options._calledWithOptions.schemaFieldsOnly
|
|
3840
|
+
?? options.schemaFieldsOnly
|
|
3841
|
+
?? defaultOptions.schemaFieldsOnly
|
|
3842
|
+
?? false;
|
|
3842
3843
|
|
|
3843
3844
|
let ret;
|
|
3844
3845
|
if (hasOnlyPrimitiveValues && !options.flattenObjectIds) {
|
|
3845
3846
|
// Fast path: if we don't have any nested objects or arrays, we only need a
|
|
3846
3847
|
// shallow clone.
|
|
3847
|
-
ret = this.$__toObjectShallow();
|
|
3848
|
+
ret = this.$__toObjectShallow(schemaFieldsOnly);
|
|
3849
|
+
} else if (schemaFieldsOnly) {
|
|
3850
|
+
ret = {};
|
|
3851
|
+
for (const path of Object.keys(this.$__schema.paths)) {
|
|
3852
|
+
const value = this.$__getValue(path);
|
|
3853
|
+
if (value === undefined) {
|
|
3854
|
+
continue;
|
|
3855
|
+
}
|
|
3856
|
+
let pathToSet = path;
|
|
3857
|
+
let objToSet = ret;
|
|
3858
|
+
if (path.indexOf('.') !== -1) {
|
|
3859
|
+
const segments = path.split('.');
|
|
3860
|
+
pathToSet = segments[segments.length - 1];
|
|
3861
|
+
for (let i = 0; i < segments.length - 1; ++i) {
|
|
3862
|
+
objToSet[segments[i]] = objToSet[segments[i]] ?? {};
|
|
3863
|
+
objToSet = objToSet[segments[i]];
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
if (value === null) {
|
|
3867
|
+
objToSet[pathToSet] = null;
|
|
3868
|
+
continue;
|
|
3869
|
+
}
|
|
3870
|
+
objToSet[pathToSet] = clone(value, options);
|
|
3871
|
+
}
|
|
3848
3872
|
} else {
|
|
3849
3873
|
ret = clone(this._doc, options) || {};
|
|
3850
3874
|
}
|
|
@@ -3910,10 +3934,12 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3910
3934
|
* Internal shallow clone alternative to `$toObject()`: much faster, no options processing
|
|
3911
3935
|
*/
|
|
3912
3936
|
|
|
3913
|
-
Document.prototype.$__toObjectShallow = function $__toObjectShallow() {
|
|
3937
|
+
Document.prototype.$__toObjectShallow = function $__toObjectShallow(schemaFieldsOnly) {
|
|
3914
3938
|
const ret = {};
|
|
3915
3939
|
if (this._doc != null) {
|
|
3916
|
-
|
|
3940
|
+
const keys = schemaFieldsOnly ? Object.keys(this.$__schema.paths) : Object.keys(this._doc);
|
|
3941
|
+
for (const key of keys) {
|
|
3942
|
+
// Safe to do this even in the schemaFieldsOnly case because we assume there's no nested paths
|
|
3917
3943
|
const value = this._doc[key];
|
|
3918
3944
|
if (value instanceof Date) {
|
|
3919
3945
|
ret[key] = new Date(value);
|
|
@@ -4066,6 +4092,7 @@ Document.prototype.$__toObjectShallow = function $__toObjectShallow() {
|
|
|
4066
4092
|
* @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
|
|
4067
4093
|
* @param {Boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
|
|
4068
4094
|
* @param {Boolean} [options.useProjection=false] - If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
|
|
4095
|
+
* @param {Boolean} [options.schemaFieldsOnly=false] - If true, the resulting object will only have fields that are defined in the document's schema. By default, `toObject()` returns all fields in the underlying document from MongoDB, including ones that are not listed in the schema.
|
|
4069
4096
|
* @return {Object} document as a plain old JavaScript object (POJO). This object may contain ObjectIds, Maps, Dates, mongodb.Binary, Buffers, and other non-POJO values.
|
|
4070
4097
|
* @see mongodb.Binary https://mongodb.github.io/node-mongodb-native/4.9/classes/Binary.html
|
|
4071
4098
|
* @api public
|
|
@@ -4336,6 +4363,7 @@ function omitDeselectedFields(self, json) {
|
|
|
4336
4363
|
* @param {Object} options
|
|
4337
4364
|
* @param {Boolean} [options.flattenMaps=true] if true, convert Maps to [POJOs](https://masteringjs.io/tutorials/fundamentals/pojo). Useful if you want to `JSON.stringify()` the result.
|
|
4338
4365
|
* @param {Boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
|
|
4366
|
+
* @param {Boolean} [options.schemaFieldsOnly=false] - If true, the resulting object will only have fields that are defined in the document's schema. By default, `toJSON()` returns all fields in the underlying document from MongoDB, including ones that are not listed in the schema.
|
|
4339
4367
|
* @return {Object}
|
|
4340
4368
|
* @see Document#toObject https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject()
|
|
4341
4369
|
* @see JSON.stringify() in JavaScript https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html
|
|
@@ -4506,6 +4534,8 @@ Document.prototype.equals = function(doc) {
|
|
|
4506
4534
|
* @param {Object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
|
|
4507
4535
|
* @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
|
|
4508
4536
|
* @param {Object} [options.options=null] Additional options like `limit` and `lean`.
|
|
4537
|
+
* @param {Boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
|
|
4538
|
+
* @param {Boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. We recommend setting this option to `true` if using transactions, especially if also populating multiple paths or paths with multiple models. MongoDB server does **not** support multiple operations in parallel on a single transaction.
|
|
4509
4539
|
* @param {Function} [callback] Callback
|
|
4510
4540
|
* @see population https://mongoosejs.com/docs/populate.html
|
|
4511
4541
|
* @see Query#select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()
|
|
@@ -4532,6 +4562,7 @@ Document.prototype.populate = async function populate() {
|
|
|
4532
4562
|
}
|
|
4533
4563
|
|
|
4534
4564
|
const paths = utils.object.vals(pop);
|
|
4565
|
+
|
|
4535
4566
|
let topLevelModel = this.constructor;
|
|
4536
4567
|
if (this.$__isNested) {
|
|
4537
4568
|
topLevelModel = this.$__[scopeSymbol].constructor;
|
|
@@ -13,6 +13,8 @@ const internalToObjectOptions = require('../../options').internalToObjectOptions
|
|
|
13
13
|
const stream = require('stream');
|
|
14
14
|
const util = require('util');
|
|
15
15
|
|
|
16
|
+
const formatToObjectOptions = Object.freeze({ ...internalToObjectOptions, copyTrustedSymbol: false });
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
|
|
18
20
|
*
|
|
@@ -384,7 +386,9 @@ function format(obj, sub, color, shell) {
|
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
const clone = require('../../helpers/clone');
|
|
387
|
-
|
|
389
|
+
// `sub` indicates `format()` was called recursively, so skip cloning because we already
|
|
390
|
+
// did a deep clone on the top-level object.
|
|
391
|
+
let x = sub ? obj : clone(obj, formatToObjectOptions);
|
|
388
392
|
const constructorName = getConstructorName(x);
|
|
389
393
|
|
|
390
394
|
if (constructorName === 'Binary') {
|
package/lib/helpers/clone.js
CHANGED
|
@@ -147,7 +147,7 @@ function cloneObject(obj, options, isArrayChild) {
|
|
|
147
147
|
} else if (seen) {
|
|
148
148
|
seen.set(obj, ret);
|
|
149
149
|
}
|
|
150
|
-
if (trustedSymbol in obj) {
|
|
150
|
+
if (trustedSymbol in obj && options?.copyTrustedSymbol !== false) {
|
|
151
151
|
ret[trustedSymbol] = obj[trustedSymbol];
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
|
|
2
3
|
function getDefaultBulkwriteResult() {
|
|
3
4
|
return {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
upserted: []
|
|
15
|
-
},
|
|
16
|
-
insertedCount: 0,
|
|
17
|
-
matchedCount: 0,
|
|
18
|
-
modifiedCount: 0,
|
|
19
|
-
deletedCount: 0,
|
|
20
|
-
upsertedCount: 0,
|
|
21
|
-
upsertedIds: {},
|
|
22
|
-
insertedIds: {},
|
|
23
|
-
n: 0
|
|
5
|
+
ok: 1,
|
|
6
|
+
nInserted: 0,
|
|
7
|
+
nUpserted: 0,
|
|
8
|
+
nMatched: 0,
|
|
9
|
+
nModified: 0,
|
|
10
|
+
nRemoved: 0,
|
|
11
|
+
upserted: [],
|
|
12
|
+
writeErrors: [],
|
|
13
|
+
insertedIds: [],
|
|
14
|
+
writeConcernErrors: []
|
|
24
15
|
};
|
|
25
16
|
}
|
|
26
17
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = function decorateBulkWriteResult(resultOrError, validationErrors, results) {
|
|
4
|
+
resultOrError.mongoose = resultOrError.mongoose || {};
|
|
5
|
+
resultOrError.mongoose.validationErrors = validationErrors;
|
|
6
|
+
resultOrError.mongoose.results = results;
|
|
7
|
+
return resultOrError;
|
|
8
|
+
};
|
package/lib/model.js
CHANGED
|
@@ -10,7 +10,6 @@ const Document = require('./document');
|
|
|
10
10
|
const DocumentNotFoundError = require('./error/notFound');
|
|
11
11
|
const EventEmitter = require('events').EventEmitter;
|
|
12
12
|
const Kareem = require('kareem');
|
|
13
|
-
const { MongoBulkWriteError } = require('mongodb');
|
|
14
13
|
const MongooseBulkWriteError = require('./error/bulkWriteError');
|
|
15
14
|
const MongooseError = require('./error/index');
|
|
16
15
|
const ObjectParameterError = require('./error/objectParameter');
|
|
@@ -69,6 +68,7 @@ const utils = require('./utils');
|
|
|
69
68
|
const minimize = require('./helpers/minimize');
|
|
70
69
|
const MongooseBulkSaveIncompleteError = require('./error/bulkSaveIncompleteError');
|
|
71
70
|
const ObjectExpectedError = require('./error/objectExpected');
|
|
71
|
+
const decorateBulkWriteResult = require('./helpers/model/decorateBulkWriteResult');
|
|
72
72
|
|
|
73
73
|
const modelCollectionSymbol = Symbol('mongoose#Model#collection');
|
|
74
74
|
const modelDbSymbol = Symbol('mongoose#Model#db');
|
|
@@ -3104,11 +3104,9 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3104
3104
|
const res = {
|
|
3105
3105
|
acknowledged: true,
|
|
3106
3106
|
insertedCount: 0,
|
|
3107
|
-
insertedIds: {}
|
|
3108
|
-
mongoose: {
|
|
3109
|
-
validationErrors: validationErrors
|
|
3110
|
-
}
|
|
3107
|
+
insertedIds: {}
|
|
3111
3108
|
};
|
|
3109
|
+
decorateBulkWriteResult(res, validationErrors, validationErrors);
|
|
3112
3110
|
return callback(null, res);
|
|
3113
3111
|
}
|
|
3114
3112
|
callback(null, []);
|
|
@@ -3161,10 +3159,7 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3161
3159
|
|
|
3162
3160
|
// Decorate with mongoose validation errors in case of unordered,
|
|
3163
3161
|
// because then still do `insertMany()`
|
|
3164
|
-
res
|
|
3165
|
-
validationErrors: validationErrors,
|
|
3166
|
-
results: results
|
|
3167
|
-
};
|
|
3162
|
+
decorateBulkWriteResult(res, validationErrors, results);
|
|
3168
3163
|
}
|
|
3169
3164
|
return callback(null, res);
|
|
3170
3165
|
}
|
|
@@ -3198,10 +3193,7 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3198
3193
|
if (error.writeErrors != null) {
|
|
3199
3194
|
for (let i = 0; i < error.writeErrors.length; ++i) {
|
|
3200
3195
|
const originalIndex = validDocIndexToOriginalIndex.get(error.writeErrors[i].index);
|
|
3201
|
-
error.writeErrors[i] = {
|
|
3202
|
-
...error.writeErrors[i],
|
|
3203
|
-
index: originalIndex
|
|
3204
|
-
};
|
|
3196
|
+
error.writeErrors[i] = { ...error.writeErrors[i], index: originalIndex };
|
|
3205
3197
|
if (!ordered) {
|
|
3206
3198
|
results[originalIndex] = error.writeErrors[i];
|
|
3207
3199
|
}
|
|
@@ -3245,10 +3237,7 @@ Model.$__insertMany = function(arr, options, callback) {
|
|
|
3245
3237
|
});
|
|
3246
3238
|
|
|
3247
3239
|
if (rawResult && ordered === false) {
|
|
3248
|
-
error
|
|
3249
|
-
validationErrors: validationErrors,
|
|
3250
|
-
results: results
|
|
3251
|
-
};
|
|
3240
|
+
decorateBulkWriteResult(error, validationErrors, results);
|
|
3252
3241
|
}
|
|
3253
3242
|
|
|
3254
3243
|
callback(error, null);
|
|
@@ -3399,7 +3388,11 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3399
3388
|
const ordered = options.ordered == null ? true : options.ordered;
|
|
3400
3389
|
|
|
3401
3390
|
if (ops.length === 0) {
|
|
3402
|
-
|
|
3391
|
+
const BulkWriteResult = this.base.driver.get().BulkWriteResult;
|
|
3392
|
+
const bulkWriteResult = new BulkWriteResult(getDefaultBulkwriteResult(), false);
|
|
3393
|
+
bulkWriteResult.n = 0;
|
|
3394
|
+
decorateBulkWriteResult(bulkWriteResult, [], []);
|
|
3395
|
+
return bulkWriteResult;
|
|
3403
3396
|
}
|
|
3404
3397
|
|
|
3405
3398
|
const validations = ops.map(op => castBulkWrite(this, op, options));
|
|
@@ -3470,7 +3463,11 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3470
3463
|
'bulkWrite'
|
|
3471
3464
|
);
|
|
3472
3465
|
}
|
|
3473
|
-
|
|
3466
|
+
const BulkWriteResult = this.base.driver.get().BulkWriteResult;
|
|
3467
|
+
const bulkWriteResult = new BulkWriteResult(getDefaultBulkwriteResult(), false);
|
|
3468
|
+
bulkWriteResult.result = getDefaultBulkwriteResult();
|
|
3469
|
+
decorateBulkWriteResult(bulkWriteResult, validationErrors, results);
|
|
3470
|
+
return bulkWriteResult;
|
|
3474
3471
|
}
|
|
3475
3472
|
|
|
3476
3473
|
let error;
|
|
@@ -3478,10 +3475,18 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3478
3475
|
then(res => ([res, null])).
|
|
3479
3476
|
catch(error => ([null, error]));
|
|
3480
3477
|
|
|
3478
|
+
const writeErrorsByIndex = {};
|
|
3479
|
+
if (error?.writeErrors) {
|
|
3480
|
+
for (const writeError of error.writeErrors) {
|
|
3481
|
+
writeErrorsByIndex[writeError.err.index] = writeError;
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
for (let i = 0; i < validOpIndexes.length; ++i) {
|
|
3485
|
+
results[validOpIndexes[i]] = writeErrorsByIndex[i] ?? null;
|
|
3486
|
+
}
|
|
3481
3487
|
if (error) {
|
|
3482
3488
|
if (validationErrors.length > 0) {
|
|
3483
|
-
error
|
|
3484
|
-
error.mongoose.validationErrors = validationErrors;
|
|
3489
|
+
decorateBulkWriteResult(error, validationErrors, results);
|
|
3485
3490
|
}
|
|
3486
3491
|
|
|
3487
3492
|
await new Promise((resolve, reject) => {
|
|
@@ -3495,9 +3500,6 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3495
3500
|
});
|
|
3496
3501
|
}
|
|
3497
3502
|
|
|
3498
|
-
for (let i = 0; i < validOpIndexes.length; ++i) {
|
|
3499
|
-
results[validOpIndexes[i]] = null;
|
|
3500
|
-
}
|
|
3501
3503
|
if (validationErrors.length > 0) {
|
|
3502
3504
|
if (options.throwOnValidationError) {
|
|
3503
3505
|
throw new MongooseBulkWriteError(
|
|
@@ -3507,9 +3509,7 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
3507
3509
|
'bulkWrite'
|
|
3508
3510
|
);
|
|
3509
3511
|
} else {
|
|
3510
|
-
res
|
|
3511
|
-
res.mongoose.validationErrors = validationErrors;
|
|
3512
|
-
res.mongoose.results = results;
|
|
3512
|
+
decorateBulkWriteResult(res, validationErrors, results);
|
|
3513
3513
|
}
|
|
3514
3514
|
}
|
|
3515
3515
|
}
|
|
@@ -3575,7 +3575,7 @@ Model.bulkSave = async function bulkSave(documents, options) {
|
|
|
3575
3575
|
(err) => ({ bulkWriteResult: null, bulkWriteError: err })
|
|
3576
3576
|
);
|
|
3577
3577
|
// If not a MongoBulkWriteError, treat this as all documents failed to save.
|
|
3578
|
-
if (bulkWriteError != null &&
|
|
3578
|
+
if (bulkWriteError != null && bulkWriteError.name !== 'MongoBulkWriteError') {
|
|
3579
3579
|
throw bulkWriteError;
|
|
3580
3580
|
}
|
|
3581
3581
|
|
|
@@ -4381,6 +4381,7 @@ Model.validate = async function validate(obj, pathsOrOptions, context) {
|
|
|
4381
4381
|
* @param {Object} [options.options=null] Additional options like `limit` and `lean`.
|
|
4382
4382
|
* @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
|
|
4383
4383
|
* @param {Boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
|
|
4384
|
+
* @param {Boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. Set this option to `true` if populating multiple paths or paths with multiple models in transactions.
|
|
4384
4385
|
* @return {Promise}
|
|
4385
4386
|
* @api public
|
|
4386
4387
|
*/
|
|
@@ -4398,11 +4399,21 @@ Model.populate = async function populate(docs, paths) {
|
|
|
4398
4399
|
}
|
|
4399
4400
|
|
|
4400
4401
|
// each path has its own query options and must be executed separately
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4402
|
+
if (paths.find(p => p.ordered)) {
|
|
4403
|
+
// Populate in series, primarily for transactions because MongoDB doesn't support multiple operations on
|
|
4404
|
+
// one transaction in parallel.
|
|
4405
|
+
// Note that if _any_ path has `ordered`, we make the top-level populate `ordered` as well.
|
|
4406
|
+
for (const path of paths) {
|
|
4407
|
+
await _populatePath(this, docs, path);
|
|
4408
|
+
}
|
|
4409
|
+
} else {
|
|
4410
|
+
// By default, populate in parallel
|
|
4411
|
+
const promises = [];
|
|
4412
|
+
for (const path of paths) {
|
|
4413
|
+
promises.push(_populatePath(this, docs, path));
|
|
4414
|
+
}
|
|
4415
|
+
await Promise.all(promises);
|
|
4404
4416
|
}
|
|
4405
|
-
await Promise.all(promises);
|
|
4406
4417
|
|
|
4407
4418
|
return docs;
|
|
4408
4419
|
};
|
|
@@ -4522,12 +4533,22 @@ async function _populatePath(model, docs, populateOptions) {
|
|
|
4522
4533
|
return;
|
|
4523
4534
|
}
|
|
4524
4535
|
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4536
|
+
if (populateOptions.ordered) {
|
|
4537
|
+
// Populate in series, primarily for transactions because MongoDB doesn't support multiple operations on
|
|
4538
|
+
// one transaction in parallel.
|
|
4539
|
+
for (const arr of params) {
|
|
4540
|
+
await _execPopulateQuery.apply(null, arr).then(valsFromDb => { vals = vals.concat(valsFromDb); });
|
|
4541
|
+
}
|
|
4542
|
+
} else {
|
|
4543
|
+
// By default, populate in parallel
|
|
4544
|
+
const promises = [];
|
|
4545
|
+
for (const arr of params) {
|
|
4546
|
+
promises.push(_execPopulateQuery.apply(null, arr).then(valsFromDb => { vals = vals.concat(valsFromDb); }));
|
|
4547
|
+
}
|
|
4548
|
+
|
|
4549
|
+
await Promise.all(promises);
|
|
4528
4550
|
}
|
|
4529
4551
|
|
|
4530
|
-
await Promise.all(promises);
|
|
4531
4552
|
|
|
4532
4553
|
for (const arr of params) {
|
|
4533
4554
|
const mod = arr[0];
|
package/lib/types/index.js
CHANGED
|
@@ -12,6 +12,7 @@ exports.Document = // @deprecate
|
|
|
12
12
|
exports.Embedded = require('./arraySubdocument');
|
|
13
13
|
|
|
14
14
|
exports.DocumentArray = require('./documentArray');
|
|
15
|
+
exports.Double = require('./double');
|
|
15
16
|
exports.Decimal128 = require('./decimal128');
|
|
16
17
|
exports.ObjectId = require('./objectid');
|
|
17
18
|
|
package/lib/utils.js
CHANGED
|
@@ -551,8 +551,8 @@ exports.populate = function populate(path, select, model, match, options, subPop
|
|
|
551
551
|
};
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
if (typeof obj.path !== 'string') {
|
|
555
|
-
throw new TypeError('utils.populate: invalid path. Expected string. Got typeof `' + typeof path + '`');
|
|
554
|
+
if (typeof obj.path !== 'string' && !(Array.isArray(obj.path) && obj.path.every(el => typeof el === 'string'))) {
|
|
555
|
+
throw new TypeError('utils.populate: invalid path. Expected string or array of strings. Got typeof `' + typeof path + '`');
|
|
556
556
|
}
|
|
557
557
|
|
|
558
558
|
return _populateObj(obj);
|
|
@@ -600,7 +600,11 @@ function _populateObj(obj) {
|
|
|
600
600
|
}
|
|
601
601
|
|
|
602
602
|
const ret = [];
|
|
603
|
-
const paths = oneSpaceRE.test(obj.path)
|
|
603
|
+
const paths = oneSpaceRE.test(obj.path)
|
|
604
|
+
? obj.path.split(manySpaceRE)
|
|
605
|
+
: Array.isArray(obj.path)
|
|
606
|
+
? obj.path
|
|
607
|
+
: [obj.path];
|
|
604
608
|
if (obj.options != null) {
|
|
605
609
|
obj.options = clone(obj.options);
|
|
606
610
|
}
|