From e1001296afd6b11b5e081373dd97751497aadac8 Mon Sep 17 00:00:00 2001 From: tosaka-n Date: Mon, 11 Dec 2023 12:35:49 +0900 Subject: [PATCH 1/3] fix: cast error when there is an elemMatch in the and clause --- lib/schema/array.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/schema/array.js b/lib/schema/array.js index 893c78f7b95..4791865a4f7 100644 --- a/lib/schema/array.js +++ b/lib/schema/array.js @@ -637,15 +637,15 @@ handle.$or = createLogicalQueryOperatorHandler('$or'); handle.$and = createLogicalQueryOperatorHandler('$and'); handle.$nor = createLogicalQueryOperatorHandler('$nor'); -function createLogicalQueryOperatorHandler(op) { - return function logicalQueryOperatorHandler(val) { +function createLogicalQueryOperatorHandler(op, context) { + return function logicalQueryOperatorHandler(val, context) { if (!Array.isArray(val)) { throw new TypeError('conditional ' + op + ' requires an array'); } const ret = []; for (const obj of val) { - ret.push(cast(this.casterConstructor.schema, obj, null, this && this.$$context)); + ret.push(cast(this.casterConstructor.schema ?? context.schema, obj, null, this && this.$$context)); } return ret; From eaf14250068d1353fc5eab38d6fdfe03f3e35d03 Mon Sep 17 00:00:00 2001 From: tosaka-n Date: Tue, 12 Dec 2023 11:24:36 +0900 Subject: [PATCH 2/3] remove: unnecessary context --- lib/schema/array.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schema/array.js b/lib/schema/array.js index 4791865a4f7..e73f16d2849 100644 --- a/lib/schema/array.js +++ b/lib/schema/array.js @@ -637,7 +637,7 @@ handle.$or = createLogicalQueryOperatorHandler('$or'); handle.$and = createLogicalQueryOperatorHandler('$and'); handle.$nor = createLogicalQueryOperatorHandler('$nor'); -function createLogicalQueryOperatorHandler(op, context) { +function createLogicalQueryOperatorHandler(op) { return function logicalQueryOperatorHandler(val, context) { if (!Array.isArray(val)) { throw new TypeError('conditional ' + op + ' requires an array'); From b052e65907ee08c70f4da4adf47c75632a071f9e Mon Sep 17 00:00:00 2001 From: tosaka-n Date: Thu, 14 Dec 2023 18:55:13 +0900 Subject: [PATCH 3/3] add: test for nested $and in $elemMatch --- test/model.query.casting.test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/model.query.casting.test.js b/test/model.query.casting.test.js index c287089461c..c7156959fc5 100644 --- a/test/model.query.casting.test.js +++ b/test/model.query.casting.test.js @@ -791,6 +791,38 @@ describe('model query casting', function() { assert.ok(res); assert.deepStrictEqual(res.map(doc => doc.arr[1].id), ['two', 'three']); }); + + it('should not throw a cast error when dealing with an array of objects in combination with $elemMatch and nested $and', async function() { + const testSchema = new Schema({ + arr: [Object] + }); + + const Test = db.model('Test', testSchema); + const obj1 = new Test({ arr: [{ id: 'one', name: 'sample1' }, { id: 'two' }] }); + await obj1.save(); + + const obj2 = new Test({ arr: [{ id: 'two', name: 'sample1' }, { id: 'three' }] }); + await obj2.save(); + + const obj3 = new Test({ arr: [{ id: 'three', name: 'sample1' }, { id: 'four' }] }); + await obj3.save(); + const res = await Test.find({ + arr: { + $elemMatch: { + $and: [ + { name: 'sample1' }, + { $or: [ + { id: 'one' }, + { id: 'two' } + ] } + ] + } + } + }).sort({ _id: 1 }); + assert.ok(res); + assert.equal(res.length, 2); + assert.deepStrictEqual(res.map(doc => doc.arr[1].id), ['two', 'three']); + }); }); function _geojsonPoint(coordinates) {