diff --git a/lib/helpers/query/castUpdate.js b/lib/helpers/query/castUpdate.js index 392eefddefc..eb69bc89a09 100644 --- a/lib/helpers/query/castUpdate.js +++ b/lib/helpers/query/castUpdate.js @@ -202,6 +202,12 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) { // an update. if (op === '$pull') { schematype = schema._getSchema(prefix + key); + if (schematype == null) { + const _res = getEmbeddedDiscriminatorPath(schema, obj, filter, prefix + key, options); + if (_res.schematype != null) { + schematype = _res.schematype; + } + } if (schematype != null && schematype.schema != null) { obj[key] = cast(schematype.schema, obj[key], options, context); hasKeys = true; diff --git a/test/model.updateOne.test.js b/test/model.updateOne.test.js index c0e917dda68..e9ae3ce43a5 100644 --- a/test/model.updateOne.test.js +++ b/test/model.updateOne.test.js @@ -3017,6 +3017,37 @@ describe('model: updateOne: ', function() { const doc = await Test.findById(_id); assert.equal(doc.subdoc['1'], 'foobar'); }); + it('handles embedded discriminators with $pull when discriminator key set in filter (gh-14675)', async function() { + const LoginSchema = new Schema({}, { discriminatorKey: 'type', _id: false }); + const UserSchema = new Schema({ + name: String, + login: LoginSchema + }); + UserSchema.path('login').discriminator('ssh-key', new Schema({ + keys: { + type: [{ + id: { type: String, required: true }, + publicKey: { type: String, required: true } + }], + default: [] + } + }, { _id: false })); + const User = db.model('Test', UserSchema); + + const { _id } = await User.create({ + login: { + type: 'ssh-key', + keys: [{ id: 'my-key', publicKey: 'test' }, { id: 'test2', publicKey: 'foo' }] + } + }); + const doc = await User.findOneAndUpdate( + { _id, 'login.type': 'ssh-key' }, + { $pull: { 'login.keys': { id: 'my-key' } } }, + { new: true } + ).exec(); + assert.equal(doc.login.keys.length, 1); + assert.equal(doc.login.keys[0].id, 'test2'); + }); }); async function delay(ms) {