From c639716a55a7e9271d5967065e9507a710803784 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Wed, 19 Jun 2024 16:39:52 -0400 Subject: [PATCH 1/3] fix(query): cast $pull using embedded discriminator schema when discriminator key is set in filter Fix #14675 --- lib/helpers/query/castUpdate.js | 6 ++++++ test/model.updateOne.test.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) 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) { From 9590792d0cd120f6282016b144d5ab357c4d85a0 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 21 Jun 2024 16:50:07 -0400 Subject: [PATCH 2/3] feat: upgrade mongodb -> 6.7.0 re: #14643 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 34d84b92fb6..8bf994564c5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", - "mongodb": "6.6.2", + "mongodb": "6.7.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", From 094277ff0465c6ce637a095bad6f4f497033c6e8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 21 Jun 2024 17:33:31 -0400 Subject: [PATCH 3/3] feat(connection): bubble up monitorCommands events to Mongoose connection if `monitorCommands` option set Fix #14611 --- lib/drivers/node-mongodb-native/connection.js | 6 +++++ test/connection.test.js | 24 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/drivers/node-mongodb-native/connection.js b/lib/drivers/node-mongodb-native/connection.js index 3c64ff2216f..6a164bca8b3 100644 --- a/lib/drivers/node-mongodb-native/connection.js +++ b/lib/drivers/node-mongodb-native/connection.js @@ -410,6 +410,12 @@ function _setClient(conn, client, options, dbName) { }); } + if (options.monitorCommands) { + client.on('commandStarted', (data) => conn.emit('commandStarted', data)); + client.on('commandFailed', (data) => conn.emit('commandFailed', data)); + client.on('commandSucceeded', (data) => conn.emit('commandSucceeded', data)); + } + conn.onOpen(); for (const i in conn.collections) { diff --git a/test/connection.test.js b/test/connection.test.js index 4554436fca8..d395be5511b 100644 --- a/test/connection.test.js +++ b/test/connection.test.js @@ -210,7 +210,7 @@ describe('connections:', function() { let conn; before(async function() { - conn = mongoose.createConnection(start.uri2); + conn = mongoose.createConnection(start.uri2, { monitorCommands: true }); await conn.asPromise(); await conn.collection('test').deleteMany({}); return conn; @@ -254,6 +254,28 @@ describe('connections:', function() { assert.equal(events[1].method, 'findOne'); assert.deepStrictEqual(events[1].result, { _id: 17, answer: 42 }); }); + + it('commandStarted, commandFailed, commandSucceeded (gh-14611)', async function() { + let events = []; + conn.on('commandStarted', event => events.push(event)); + conn.on('commandFailed', event => events.push(event)); + conn.on('commandSucceeded', event => events.push(event)); + + await conn.collection('test').insertOne({ _id: 14611, answer: 42 }); + assert.equal(events.length, 2); + assert.equal(events[0].constructor.name, 'CommandStartedEvent'); + assert.equal(events[0].commandName, 'insert'); + assert.equal(events[1].constructor.name, 'CommandSucceededEvent'); + assert.equal(events[1].requestId, events[0].requestId); + + events = []; + await conn.createCollection('tests', { capped: 1024 }).catch(() => {}); + assert.equal(events.length, 2); + assert.equal(events[0].constructor.name, 'CommandStartedEvent'); + assert.equal(events[0].commandName, 'create'); + assert.equal(events[1].constructor.name, 'CommandFailedEvent'); + assert.equal(events[1].requestId, events[0].requestId); + }); }); it('should allow closing a closed connection', async function() {