Skip to content

Commit b76ca9d

Browse files
authored
Merge pull request #15046 from Automattic/vkarpov15/gh-15040
fix(model+query): support overwriteDiscriminatorKey for bulkWrite updateOne and updateMany, allow inferring discriminator key from update
2 parents b34aba6 + 83db613 commit b76ca9d

File tree

4 files changed

+71
-14
lines changed

4 files changed

+71
-14
lines changed

lib/helpers/model/castBulkWrite.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
104104
op['updateOne']['update'] = castUpdate(model.schema, update, {
105105
strict: strict,
106106
upsert: op['updateOne'].upsert,
107-
arrayFilters: op['updateOne'].arrayFilters
107+
arrayFilters: op['updateOne'].arrayFilters,
108+
overwriteDiscriminatorKey: op['updateOne'].overwriteDiscriminatorKey
108109
}, model, op['updateOne']['filter']);
109110
} catch (error) {
110111
return callback(error, null);
@@ -164,7 +165,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
164165
op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
165166
strict: strict,
166167
upsert: op['updateMany'].upsert,
167-
arrayFilters: op['updateMany'].arrayFilters
168+
arrayFilters: op['updateMany'].arrayFilters,
169+
overwriteDiscriminatorKey: op['updateMany'].overwriteDiscriminatorKey
168170
}, model, op['updateMany']['filter']);
169171
} catch (error) {
170172
return callback(error, null);

lib/helpers/query/castUpdate.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const ValidationError = require('../../error/validation');
88
const castNumber = require('../../cast/number');
99
const cast = require('../../cast');
1010
const getConstructorName = require('../getConstructorName');
11+
const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
1112
const getEmbeddedDiscriminatorPath = require('./getEmbeddedDiscriminatorPath');
1213
const handleImmutable = require('./handleImmutable');
1314
const moveImmutableProperties = require('../update/moveImmutableProperties');
@@ -62,6 +63,27 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
6263
return obj;
6364
}
6465

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+
6587
if (options.upsert) {
6688
moveImmutableProperties(schema, obj, context);
6789
}

lib/query.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4700,18 +4700,6 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
47004700
upsert = this.options.upsert;
47014701
}
47024702

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-
47154703
return castUpdate(schema, obj, {
47164704
strict: this._mongooseOptions.strict,
47174705
upsert: upsert,

test/model.test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4174,6 +4174,51 @@ describe('Model', function() {
41744174
assert.strictEqual(r2.testArray[0].nonexistentProp, undefined);
41754175
});
41764176

4177+
it('handles overwriteDiscriminatorKey (gh-15040)', async function() {
4178+
const dSchema1 = new mongoose.Schema({
4179+
field1: String
4180+
});
4181+
const dSchema2 = new mongoose.Schema({
4182+
field2: String
4183+
});
4184+
const baseSchema = new mongoose.Schema({
4185+
field: String,
4186+
key: String
4187+
}, { discriminatorKey: 'key' });
4188+
const type1Key = 'Type1';
4189+
const type2Key = 'Type2';
4190+
4191+
baseSchema.discriminator(type1Key, dSchema1);
4192+
baseSchema.discriminator(type2Key, dSchema2);
4193+
4194+
const TestModel = db.model('Test', baseSchema);
4195+
4196+
const test = new TestModel({
4197+
field: 'base field',
4198+
key: type1Key,
4199+
field1: 'field1'
4200+
});
4201+
const r1 = await test.save();
4202+
assert.equal(r1.field1, 'field1');
4203+
assert.equal(r1.key, type1Key);
4204+
4205+
const field2 = 'field2';
4206+
await TestModel.bulkWrite([{
4207+
updateOne: {
4208+
filter: { _id: r1._id },
4209+
update: {
4210+
key: type2Key,
4211+
field2
4212+
},
4213+
overwriteDiscriminatorKey: true
4214+
}
4215+
}]);
4216+
4217+
const r2 = await TestModel.findById(r1._id);
4218+
assert.equal(r2.key, type2Key);
4219+
assert.equal(r2.field2, field2);
4220+
});
4221+
41774222
it('with child timestamps and array filters (gh-7032)', async function() {
41784223
const childSchema = new Schema({ name: String }, { timestamps: true });
41794224

0 commit comments

Comments
 (0)