Skip to content

Commit

Permalink
Fix preparation of $elemMatch operators in queries
Browse files Browse the repository at this point in the history
  • Loading branch information
alcaeus committed Apr 13, 2021
1 parent 05c9a25 commit ea05126
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 9 deletions.
7 changes: 6 additions & 1 deletion lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -1321,7 +1321,12 @@ private function prepareQueryExpression(array $expression, ClassMetadata $class)
continue;
}

// Recursively process expressions within a $not operator
// Recursively process expressions within a $not or $elemMatch operator
if ($k === '$elemMatch' && is_array($v)) {
$expression[$k] = $this->prepareQueryOrNewObj($v, false);
continue;
}

if ($k === '$not' && is_array($v)) {
$expression[$k] = $this->prepareQueryExpression($v, $class);
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public function testPrepareQueryOrNewObjWithHashIdAndInOperators($hashId)
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['_id' => ['$elemMatch' => $hashId]];
$expected = ['_id' => ['$elemMatch' => (object) $hashId]];
$expected = ['_id' => ['$elemMatch' => $hashId]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand All @@ -208,7 +208,7 @@ public function testPrepareQueryOrNewObjWithHashIdAndInOperators($hashId)
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['_id' => ['$not' => ['$elemMatch' => $hashId]]];
$expected = ['_id' => ['$not' => ['$elemMatch' => (object) $hashId]]];
$expected = ['_id' => ['$not' => ['$elemMatch' => $hashId]]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand Down Expand Up @@ -396,7 +396,7 @@ public function testPrepareQueryOrNewObjWithSimpleReferenceToTargetDocumentWithH
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['simpleRef' => ['$elemMatch' => $hashId]];
$expected = ['simpleRef' => ['$elemMatch' => (object) $hashId]];
$expected = ['simpleRef' => ['$elemMatch' => $hashId]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand All @@ -406,7 +406,7 @@ public function testPrepareQueryOrNewObjWithSimpleReferenceToTargetDocumentWithH
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['simpleRef' => ['$not' => ['$elemMatch' => $hashId]]];
$expected = ['simpleRef' => ['$not' => ['$elemMatch' => (object) $hashId]]];
$expected = ['simpleRef' => ['$not' => ['$elemMatch' => $hashId]]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand Down Expand Up @@ -473,7 +473,7 @@ public function testPrepareQueryOrNewObjWithDBRefReferenceToTargetDocumentWithHa
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['complexRef.id' => ['$elemMatch' => $hashId]];
$expected = ['complexRef.$id' => ['$elemMatch' => (object) $hashId]];
$expected = ['complexRef.$id' => ['$elemMatch' => $hashId]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand All @@ -483,7 +483,7 @@ public function testPrepareQueryOrNewObjWithDBRefReferenceToTargetDocumentWithHa
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['complexRef.id' => ['$not' => ['$elemMatch' => $hashId]]];
$expected = ['complexRef.$id' => ['$not' => ['$elemMatch' => (object) $hashId]]];
$expected = ['complexRef.$id' => ['$not' => ['$elemMatch' => $hashId]]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand Down Expand Up @@ -587,7 +587,7 @@ public function testPrepareQueryOrNewObjWithEmbeddedReferenceToTargetDocumentWit
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['embeddedRef.id' => ['$elemMatch' => $hashId]];
$expected = ['embeddedRef.id' => ['$elemMatch' => (object) $hashId]];
$expected = ['embeddedRef.id' => ['$elemMatch' => $hashId]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand All @@ -597,7 +597,7 @@ public function testPrepareQueryOrNewObjWithEmbeddedReferenceToTargetDocumentWit
$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

$value = ['embeddedRef.id' => ['$not' => ['$elemMatch' => $hashId]]];
$expected = ['embeddedRef.id' => ['$not' => ['$elemMatch' => (object) $hashId]]];
$expected = ['embeddedRef.id' => ['$not' => ['$elemMatch' => $hashId]]];

$this->assertEquals($expected, $documentPersister->prepareQueryOrNewObj($value));

Expand Down
48 changes: 48 additions & 0 deletions tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2251Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Doctrine\ODM\MongoDB\Tests\Functional\Ticket;

use Doctrine\ODM\MongoDB\Tests\BaseTest;
use Documents\User;
use MongoDB\BSON\ObjectId;

class GH2251Test extends BaseTest
{
/**
* @testWith ["groups"]
* ["groupsSimple"]
*/
public function testElemMatchQuery(string $fieldName)
{
$builder = $this->dm->createQueryBuilder(User::class);

$objectIds = [
new ObjectId('5fae9a775ef4492e3c72b3f3'),
new ObjectId('5fae9a775ef4492e3c72b3f4'),
];

$notIn = $builder->expr()->notIn($objectIds);
$elemMatch = $builder->expr()
->field($fieldName)
->elemMatch($notIn);

$builder->addNor(
$elemMatch
);

$this->assertSame(
[
'$nor' => [
[
$fieldName => [
'$elemMatch' => ['$nin' => $objectIds],
],
],
],
],
$builder->getQueryArray()
);
}
}

0 comments on commit ea05126

Please sign in to comment.