mongoose 8.8.2 → 8.8.4
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/document.js +37 -43
- package/lib/helpers/model/castBulkWrite.js +4 -2
- package/lib/helpers/populate/assignVals.js +1 -5
- package/lib/helpers/populate/getModelsMapForPopulate.js +19 -0
- package/lib/helpers/query/castUpdate.js +22 -0
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +7 -1
- package/lib/model.js +1 -1
- package/lib/options/saveOptions.js +2 -0
- package/lib/plugins/saveSubdocs.js +6 -2
- package/lib/query.js +0 -12
- package/lib/schema.js +14 -3
- package/package.json +5 -5
package/lib/document.js
CHANGED
|
@@ -2711,7 +2711,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2711
2711
|
|
|
2712
2712
|
if (!isNestedValidate) {
|
|
2713
2713
|
// If we're validating a subdocument, all this logic will run anyway on the top-level document, so skip for subdocuments
|
|
2714
|
-
const subdocs = doc.$getAllSubdocs();
|
|
2714
|
+
const subdocs = doc.$getAllSubdocs({ useCache: true });
|
|
2715
2715
|
const modifiedPaths = doc.modifiedPaths();
|
|
2716
2716
|
for (const subdoc of subdocs) {
|
|
2717
2717
|
if (subdoc.$basePath) {
|
|
@@ -3482,7 +3482,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3482
3482
|
let _this = this;
|
|
3483
3483
|
|
|
3484
3484
|
// Skip for subdocuments
|
|
3485
|
-
const subdocs = !this.$isSubdocument ? this.$getAllSubdocs() : null;
|
|
3485
|
+
const subdocs = !this.$isSubdocument ? this.$getAllSubdocs({ useCache: true }) : null;
|
|
3486
3486
|
if (subdocs && subdocs.length > 0) {
|
|
3487
3487
|
for (const subdoc of subdocs) {
|
|
3488
3488
|
subdoc.$__reset();
|
|
@@ -3672,6 +3672,7 @@ Document.prototype.$__getArrayPathsToValidate = function() {
|
|
|
3672
3672
|
/**
|
|
3673
3673
|
* Get all subdocs (by bfs)
|
|
3674
3674
|
*
|
|
3675
|
+
* @param {Object} [options] options. Currently for internal use.
|
|
3675
3676
|
* @return {Array}
|
|
3676
3677
|
* @api public
|
|
3677
3678
|
* @method $getAllSubdocs
|
|
@@ -3679,57 +3680,50 @@ Document.prototype.$__getArrayPathsToValidate = function() {
|
|
|
3679
3680
|
* @instance
|
|
3680
3681
|
*/
|
|
3681
3682
|
|
|
3682
|
-
Document.prototype.$getAllSubdocs = function() {
|
|
3683
|
+
Document.prototype.$getAllSubdocs = function(options) {
|
|
3684
|
+
if (options?.useCache && this.$__.saveOptions?.__subdocs) {
|
|
3685
|
+
return this.$__.saveOptions.__subdocs;
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3683
3688
|
DocumentArray || (DocumentArray = require('./types/documentArray'));
|
|
3684
3689
|
Embedded = Embedded || require('./types/arraySubdocument');
|
|
3685
3690
|
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
val = doc._doc[path];
|
|
3694
|
-
isNested = true;
|
|
3695
|
-
} else {
|
|
3696
|
-
val = doc[path];
|
|
3691
|
+
const subDocs = [];
|
|
3692
|
+
function getSubdocs(doc) {
|
|
3693
|
+
const newSubdocs = [];
|
|
3694
|
+
for (const { path } of doc.$__schema.childSchemas) {
|
|
3695
|
+
const val = doc.$__getValue(path);
|
|
3696
|
+
if (val == null) {
|
|
3697
|
+
continue;
|
|
3697
3698
|
}
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
seed = Object.keys(val._doc).reduce(function(seed, path) {
|
|
3707
|
-
return docReducer(val, seed, path);
|
|
3708
|
-
}, seed);
|
|
3709
|
-
seed.push(val);
|
|
3710
|
-
} else if (val && utils.isMongooseDocumentArray(val)) {
|
|
3711
|
-
val.forEach(function _docReduce(doc) {
|
|
3712
|
-
if (!doc || !doc._doc) {
|
|
3713
|
-
return;
|
|
3699
|
+
if (val.$__) {
|
|
3700
|
+
newSubdocs.push(val);
|
|
3701
|
+
}
|
|
3702
|
+
if (Array.isArray(val)) {
|
|
3703
|
+
for (const el of val) {
|
|
3704
|
+
if (el != null && el.$__) {
|
|
3705
|
+
newSubdocs.push(el);
|
|
3706
|
+
}
|
|
3714
3707
|
}
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3708
|
+
}
|
|
3709
|
+
if (val instanceof Map) {
|
|
3710
|
+
for (const el of val.values()) {
|
|
3711
|
+
if (el != null && el.$__) {
|
|
3712
|
+
newSubdocs.push(el);
|
|
3713
|
+
}
|
|
3720
3714
|
}
|
|
3721
|
-
});
|
|
3722
|
-
} else if (isNested && val != null) {
|
|
3723
|
-
for (const path of Object.keys(val)) {
|
|
3724
|
-
docReducer(val, seed, path);
|
|
3725
3715
|
}
|
|
3726
3716
|
}
|
|
3727
|
-
|
|
3717
|
+
for (const subdoc of newSubdocs) {
|
|
3718
|
+
getSubdocs(subdoc);
|
|
3719
|
+
}
|
|
3720
|
+
subDocs.push(...newSubdocs);
|
|
3728
3721
|
}
|
|
3729
3722
|
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3723
|
+
getSubdocs(this);
|
|
3724
|
+
|
|
3725
|
+
if (this.$__.saveOptions) {
|
|
3726
|
+
this.$__.saveOptions.__subdocs = subDocs;
|
|
3733
3727
|
}
|
|
3734
3728
|
|
|
3735
3729
|
return subDocs;
|
|
@@ -104,7 +104,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
|
|
|
104
104
|
op['updateOne']['update'] = castUpdate(model.schema, update, {
|
|
105
105
|
strict: strict,
|
|
106
106
|
upsert: op['updateOne'].upsert,
|
|
107
|
-
arrayFilters: op['updateOne'].arrayFilters
|
|
107
|
+
arrayFilters: op['updateOne'].arrayFilters,
|
|
108
|
+
overwriteDiscriminatorKey: op['updateOne'].overwriteDiscriminatorKey
|
|
108
109
|
}, model, op['updateOne']['filter']);
|
|
109
110
|
} catch (error) {
|
|
110
111
|
return callback(error, null);
|
|
@@ -164,7 +165,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
|
|
|
164
165
|
op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
|
|
165
166
|
strict: strict,
|
|
166
167
|
upsert: op['updateMany'].upsert,
|
|
167
|
-
arrayFilters: op['updateMany'].arrayFilters
|
|
168
|
+
arrayFilters: op['updateMany'].arrayFilters,
|
|
169
|
+
overwriteDiscriminatorKey: op['updateMany'].overwriteDiscriminatorKey
|
|
168
170
|
}, model, op['updateMany']['filter']);
|
|
169
171
|
} catch (error) {
|
|
170
172
|
return callback(error, null);
|
|
@@ -249,7 +249,7 @@ function numDocs(v) {
|
|
|
249
249
|
|
|
250
250
|
function valueFilter(val, assignmentOpts, populateOptions, allIds) {
|
|
251
251
|
const userSpecifiedTransform = typeof populateOptions.transform === 'function';
|
|
252
|
-
const transform = userSpecifiedTransform ? populateOptions.transform :
|
|
252
|
+
const transform = userSpecifiedTransform ? populateOptions.transform : v => v;
|
|
253
253
|
if (Array.isArray(val)) {
|
|
254
254
|
// find logic
|
|
255
255
|
const ret = [];
|
|
@@ -341,7 +341,3 @@ function isPopulatedObject(obj) {
|
|
|
341
341
|
obj.$__ != null ||
|
|
342
342
|
leanPopulateMap.has(obj);
|
|
343
343
|
}
|
|
344
|
-
|
|
345
|
-
function noop(v) {
|
|
346
|
-
return v;
|
|
347
|
-
}
|
|
@@ -184,6 +184,15 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
|
|
|
184
184
|
if (hasMatchFunction) {
|
|
185
185
|
match = match.call(doc, doc);
|
|
186
186
|
}
|
|
187
|
+
if (Array.isArray(match)) {
|
|
188
|
+
for (const item of match) {
|
|
189
|
+
if (item != null && item.$where) {
|
|
190
|
+
throw new MongooseError('Cannot use $where filter with populate() match');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
} else if (match != null && match.$where != null) {
|
|
194
|
+
throw new MongooseError('Cannot use $where filter with populate() match');
|
|
195
|
+
}
|
|
187
196
|
data.match = match;
|
|
188
197
|
data.hasMatchFunction = hasMatchFunction;
|
|
189
198
|
data.isRefPath = isRefPath;
|
|
@@ -447,6 +456,16 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
|
|
|
447
456
|
data.match = match;
|
|
448
457
|
data.hasMatchFunction = hasMatchFunction;
|
|
449
458
|
|
|
459
|
+
if (Array.isArray(match)) {
|
|
460
|
+
for (const item of match) {
|
|
461
|
+
if (item != null && item.$where) {
|
|
462
|
+
throw new MongooseError('Cannot use $where filter with populate() match');
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} else if (match != null && match.$where != null) {
|
|
466
|
+
throw new MongooseError('Cannot use $where filter with populate() match');
|
|
467
|
+
}
|
|
468
|
+
|
|
450
469
|
// Get local fields
|
|
451
470
|
const ret = _getLocalFieldValues(doc, localField, model, options, virtual);
|
|
452
471
|
|
|
@@ -8,6 +8,7 @@ const ValidationError = require('../../error/validation');
|
|
|
8
8
|
const castNumber = require('../../cast/number');
|
|
9
9
|
const cast = require('../../cast');
|
|
10
10
|
const getConstructorName = require('../getConstructorName');
|
|
11
|
+
const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
|
|
11
12
|
const getEmbeddedDiscriminatorPath = require('./getEmbeddedDiscriminatorPath');
|
|
12
13
|
const handleImmutable = require('./handleImmutable');
|
|
13
14
|
const moveImmutableProperties = require('../update/moveImmutableProperties');
|
|
@@ -62,6 +63,27 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
|
|
|
62
63
|
return obj;
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
if (schema != null &&
|
|
67
|
+
filter != null &&
|
|
68
|
+
utils.hasUserDefinedProperty(filter, schema.options.discriminatorKey) &&
|
|
69
|
+
typeof filter[schema.options.discriminatorKey] !== 'object' &&
|
|
70
|
+
schema.discriminators != null) {
|
|
71
|
+
const discriminatorValue = filter[schema.options.discriminatorKey];
|
|
72
|
+
const byValue = getDiscriminatorByValue(context.model.discriminators, discriminatorValue);
|
|
73
|
+
schema = schema.discriminators[discriminatorValue] ||
|
|
74
|
+
(byValue && byValue.schema) ||
|
|
75
|
+
schema;
|
|
76
|
+
} else if (schema != null &&
|
|
77
|
+
options.overwriteDiscriminatorKey &&
|
|
78
|
+
utils.hasUserDefinedProperty(obj, schema.options.discriminatorKey) &&
|
|
79
|
+
schema.discriminators != null) {
|
|
80
|
+
const discriminatorValue = obj[schema.options.discriminatorKey];
|
|
81
|
+
const byValue = getDiscriminatorByValue(context.model.discriminators, discriminatorValue);
|
|
82
|
+
schema = schema.discriminators[discriminatorValue] ||
|
|
83
|
+
(byValue && byValue.schema) ||
|
|
84
|
+
schema;
|
|
85
|
+
}
|
|
86
|
+
|
|
65
87
|
if (options.upsert) {
|
|
66
88
|
moveImmutableProperties(schema, obj, context);
|
|
67
89
|
}
|
|
@@ -28,7 +28,8 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
|
|
|
28
28
|
const updatedPathsByFilter = updatedPathsByArrayFilter(update);
|
|
29
29
|
|
|
30
30
|
for (let i = 0; i < parts.length; ++i) {
|
|
31
|
-
const
|
|
31
|
+
const originalSubpath = parts.slice(0, i + 1).join('.');
|
|
32
|
+
const subpath = cleanPositionalOperators(originalSubpath);
|
|
32
33
|
schematype = schema.path(subpath);
|
|
33
34
|
if (schematype == null) {
|
|
34
35
|
continue;
|
|
@@ -56,6 +57,11 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
|
|
|
56
57
|
discriminatorKey = filter[wrapperPath].$elemMatch[key];
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
const discriminatorKeyUpdatePath = originalSubpath + '.' + key;
|
|
61
|
+
if (discriminatorKeyUpdatePath in update) {
|
|
62
|
+
discriminatorKey = update[discriminatorKeyUpdatePath];
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
if (discriminatorValuePath in update) {
|
|
60
66
|
discriminatorKey = update[discriminatorValuePath];
|
|
61
67
|
}
|
package/lib/model.js
CHANGED
|
@@ -3146,7 +3146,7 @@ function _setIsNew(doc, val) {
|
|
|
3146
3146
|
doc.$emit('isNew', val);
|
|
3147
3147
|
doc.constructor.emit('isNew', val);
|
|
3148
3148
|
|
|
3149
|
-
const subdocs = doc.$getAllSubdocs();
|
|
3149
|
+
const subdocs = doc.$getAllSubdocs({ useCache: true });
|
|
3150
3150
|
for (const subdoc of subdocs) {
|
|
3151
3151
|
subdoc.$isNew = val;
|
|
3152
3152
|
subdoc.$emit('isNew', val);
|
|
@@ -15,7 +15,7 @@ module.exports = function saveSubdocs(schema) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const _this = this;
|
|
18
|
-
const subdocs = this.$getAllSubdocs();
|
|
18
|
+
const subdocs = this.$getAllSubdocs({ useCache: true });
|
|
19
19
|
|
|
20
20
|
if (!subdocs.length) {
|
|
21
21
|
next();
|
|
@@ -27,6 +27,10 @@ module.exports = function saveSubdocs(schema) {
|
|
|
27
27
|
cb(err);
|
|
28
28
|
});
|
|
29
29
|
}, function(error) {
|
|
30
|
+
// Invalidate subdocs cache because subdoc pre hooks can add new subdocuments
|
|
31
|
+
if (_this.$__.saveOptions) {
|
|
32
|
+
_this.$__.saveOptions.__subdocs = null;
|
|
33
|
+
}
|
|
30
34
|
if (error) {
|
|
31
35
|
return _this.$__schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
|
|
32
36
|
next(error);
|
|
@@ -64,7 +68,7 @@ module.exports = function saveSubdocs(schema) {
|
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
const _this = this;
|
|
67
|
-
const subdocs = this.$getAllSubdocs();
|
|
71
|
+
const subdocs = this.$getAllSubdocs({ useCache: true });
|
|
68
72
|
|
|
69
73
|
if (!subdocs.length) {
|
|
70
74
|
return;
|
package/lib/query.js
CHANGED
|
@@ -4700,18 +4700,6 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
|
|
|
4700
4700
|
upsert = this.options.upsert;
|
|
4701
4701
|
}
|
|
4702
4702
|
|
|
4703
|
-
const filter = this._conditions;
|
|
4704
|
-
if (schema != null &&
|
|
4705
|
-
utils.hasUserDefinedProperty(filter, schema.options.discriminatorKey) &&
|
|
4706
|
-
typeof filter[schema.options.discriminatorKey] !== 'object' &&
|
|
4707
|
-
schema.discriminators != null) {
|
|
4708
|
-
const discriminatorValue = filter[schema.options.discriminatorKey];
|
|
4709
|
-
const byValue = getDiscriminatorByValue(this.model.discriminators, discriminatorValue);
|
|
4710
|
-
schema = schema.discriminators[discriminatorValue] ||
|
|
4711
|
-
(byValue && byValue.schema) ||
|
|
4712
|
-
schema;
|
|
4713
|
-
}
|
|
4714
|
-
|
|
4715
4703
|
return castUpdate(schema, obj, {
|
|
4716
4704
|
strict: this._mongooseOptions.strict,
|
|
4717
4705
|
upsert: upsert,
|
package/lib/schema.js
CHANGED
|
@@ -1126,6 +1126,13 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1126
1126
|
|
|
1127
1127
|
this.paths[mapPath] = schemaType.$__schemaType;
|
|
1128
1128
|
this.mapPaths.push(this.paths[mapPath]);
|
|
1129
|
+
if (schemaType.$__schemaType.$isSingleNested) {
|
|
1130
|
+
this.childSchemas.push({
|
|
1131
|
+
schema: schemaType.$__schemaType.schema,
|
|
1132
|
+
model: schemaType.$__schemaType.caster,
|
|
1133
|
+
path: path
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1129
1136
|
}
|
|
1130
1137
|
|
|
1131
1138
|
if (schemaType.$isSingleNested) {
|
|
@@ -1154,7 +1161,8 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1154
1161
|
schemaType.caster.base = this.base;
|
|
1155
1162
|
this.childSchemas.push({
|
|
1156
1163
|
schema: schemaType.schema,
|
|
1157
|
-
model: schemaType.caster
|
|
1164
|
+
model: schemaType.caster,
|
|
1165
|
+
path: path
|
|
1158
1166
|
});
|
|
1159
1167
|
} else if (schemaType.$isMongooseDocumentArray) {
|
|
1160
1168
|
Object.defineProperty(schemaType.schema, 'base', {
|
|
@@ -1167,7 +1175,8 @@ Schema.prototype.path = function(path, obj) {
|
|
|
1167
1175
|
schemaType.casterConstructor.base = this.base;
|
|
1168
1176
|
this.childSchemas.push({
|
|
1169
1177
|
schema: schemaType.schema,
|
|
1170
|
-
model: schemaType.casterConstructor
|
|
1178
|
+
model: schemaType.casterConstructor,
|
|
1179
|
+
path: path
|
|
1171
1180
|
});
|
|
1172
1181
|
}
|
|
1173
1182
|
|
|
@@ -1235,7 +1244,9 @@ function gatherChildSchemas(schema) {
|
|
|
1235
1244
|
for (const path of Object.keys(schema.paths)) {
|
|
1236
1245
|
const schematype = schema.paths[path];
|
|
1237
1246
|
if (schematype.$isMongooseDocumentArray || schematype.$isSingleNested) {
|
|
1238
|
-
childSchemas.push({ schema: schematype.schema, model: schematype.caster });
|
|
1247
|
+
childSchemas.push({ schema: schematype.schema, model: schematype.caster, path: path });
|
|
1248
|
+
} else if (schematype.$isSchemaMap && schematype.$__schemaType.$isSingleNested) {
|
|
1249
|
+
childSchemas.push({ schema: schematype.$__schemaType.schema, model: schematype.$__schemaType.caster, path: path });
|
|
1239
1250
|
}
|
|
1240
1251
|
}
|
|
1241
1252
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "8.8.
|
|
4
|
+
"version": "8.8.4",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"highlight.js": "11.10.0",
|
|
53
53
|
"lodash.isequal": "4.5.0",
|
|
54
54
|
"lodash.isequalwith": "4.4.0",
|
|
55
|
-
"markdownlint-cli2": "^0.
|
|
56
|
-
"marked": "
|
|
55
|
+
"markdownlint-cli2": "^0.15.0",
|
|
56
|
+
"marked": "15.0.3",
|
|
57
57
|
"mkdirp": "^3.0.1",
|
|
58
58
|
"mocha": "10.8.2",
|
|
59
59
|
"moment": "2.30.1",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"sinon": "19.0.2",
|
|
66
66
|
"stream-browserify": "3.0.0",
|
|
67
67
|
"tsd": "0.31.2",
|
|
68
|
-
"typescript": "5.
|
|
69
|
-
"uuid": "11.0.
|
|
68
|
+
"typescript": "5.7.2",
|
|
69
|
+
"uuid": "11.0.3",
|
|
70
70
|
"webpack": "5.96.1"
|
|
71
71
|
},
|
|
72
72
|
"directories": {
|