Skip to content

Commit

Permalink
Add support for using $text operator in a aggregation with a filter
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed Feb 28, 2025
1 parent fd0ad45 commit 8c956c6
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
16 changes: 15 additions & 1 deletion lib/Doctrine/ODM/MongoDB/Aggregation/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ public function getAggregation(array $options = []): IterableResult
* @param bool $applyFilters Whether to apply filters on the aggregation
* pipeline stage
*
* For pipelines where the first stage is a $match stage, it will merge
* the document filters with the existing stage in a logical $and. This is
* required as $text operator can be used anywhere in the first $match stage
* or in the document filters.
*
* For pipelines where the first stage is a $geoNear stage, it will apply
* the document filters and discriminator queries to the query portion of
* the geoNear operation. For all other pipelines, it prepends a $match stage
Expand Down Expand Up @@ -314,7 +319,16 @@ public function getPipeline(/* bool $applyFilters = true */): array

$matchExpression = $this->applyFilters([]);
if ($matchExpression !== []) {
array_unshift($pipeline, ['$match' => $matchExpression]);
if (! empty($pipeline[0]['$match'])) {
$pipeline[0]['$match'] = [
'$and' => [
$matchExpression,
$pipeline[0]['$match'],
],
];
} else {
array_unshift($pipeline, ['$match' => $matchExpression]);
}
}

return $pipeline;
Expand Down
33 changes: 33 additions & 0 deletions tests/Doctrine/ODM/MongoDB/Tests/Aggregation/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,39 @@ public function testBuilderAppliesFilterAndDiscriminatorWithMatchStage(): void
self::assertEquals($expectedPipeline, $builder->getPipeline());
}

public function testBuilderMergeFilterAndDiscriminatorWithMatchStage(): void
{
$this->dm->getFilterCollection()->enable('testFilter');
$filter = $this->dm->getFilterCollection()->getFilter('testFilter');
$filter->setParameter('class', GuestServer::class);
$filter->setParameter('field', 'filtered');
$filter->setParameter('value', true);

$builder = $this->dm->createAggregationBuilder(GuestServer::class);
$builder
->match()
->text('Paul');

$expectedPipeline = [
[
'$match' => [
'$and' => [
[
'$and' => [
['stype' => 'server_guest'],
['filtered' => true],
],
],
['$text' => ['$search' => 'Paul']],
],
],

],
];

self::assertEquals($expectedPipeline, $builder->getPipeline());
}

public function testBuilderAppliesFilterAndDiscriminatorWithGeoNearStage(): void
{
$this->dm->getFilterCollection()->enable('testFilter');
Expand Down
18 changes: 18 additions & 0 deletions tests/Doctrine/ODM/MongoDB/Tests/Functional/FilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,22 @@ public function testMultipleFiltersOnSameField(): void
*/
self::assertEmpty($this->getUsernamesWithFindAll());
}

public function testFilterOnMatchStageUsingTextOperator(): void
{
$this->dm->getDocumentCollection(User::class)->createIndex(['username' => 'text']);

$this->fc->enable('testFilter');
$testFilter = $this->fc->getFilter('testFilter');
$testFilter->setParameter('class', User::class);
$testFilter->setParameter('field', 'hits');
$testFilter->setParameter('value', 10);

$builder = $this->dm->createAggregationBuilder(User::class)
->match()
->field('username')
->text('John');

self::assertCount(1, $builder->getAggregation()->execute());
}
}

0 comments on commit 8c956c6

Please sign in to comment.