Skip to content

Commit 8c956c6

Browse files
committed
Add support for using $text operator in a aggregation with a filter
1 parent fd0ad45 commit 8c956c6

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

lib/Doctrine/ODM/MongoDB/Aggregation/Builder.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ public function getAggregation(array $options = []): IterableResult
264264
* @param bool $applyFilters Whether to apply filters on the aggregation
265265
* pipeline stage
266266
*
267+
* For pipelines where the first stage is a $match stage, it will merge
268+
* the document filters with the existing stage in a logical $and. This is
269+
* required as $text operator can be used anywhere in the first $match stage
270+
* or in the document filters.
271+
*
267272
* For pipelines where the first stage is a $geoNear stage, it will apply
268273
* the document filters and discriminator queries to the query portion of
269274
* the geoNear operation. For all other pipelines, it prepends a $match stage
@@ -314,7 +319,16 @@ public function getPipeline(/* bool $applyFilters = true */): array
314319

315320
$matchExpression = $this->applyFilters([]);
316321
if ($matchExpression !== []) {
317-
array_unshift($pipeline, ['$match' => $matchExpression]);
322+
if (! empty($pipeline[0]['$match'])) {
323+
$pipeline[0]['$match'] = [
324+
'$and' => [
325+
$matchExpression,
326+
$pipeline[0]['$match'],
327+
],
328+
];
329+
} else {
330+
array_unshift($pipeline, ['$match' => $matchExpression]);
331+
}
318332
}
319333

320334
return $pipeline;

tests/Doctrine/ODM/MongoDB/Tests/Aggregation/BuilderTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,39 @@ public function testBuilderAppliesFilterAndDiscriminatorWithMatchStage(): void
368368
self::assertEquals($expectedPipeline, $builder->getPipeline());
369369
}
370370

371+
public function testBuilderMergeFilterAndDiscriminatorWithMatchStage(): void
372+
{
373+
$this->dm->getFilterCollection()->enable('testFilter');
374+
$filter = $this->dm->getFilterCollection()->getFilter('testFilter');
375+
$filter->setParameter('class', GuestServer::class);
376+
$filter->setParameter('field', 'filtered');
377+
$filter->setParameter('value', true);
378+
379+
$builder = $this->dm->createAggregationBuilder(GuestServer::class);
380+
$builder
381+
->match()
382+
->text('Paul');
383+
384+
$expectedPipeline = [
385+
[
386+
'$match' => [
387+
'$and' => [
388+
[
389+
'$and' => [
390+
['stype' => 'server_guest'],
391+
['filtered' => true],
392+
],
393+
],
394+
['$text' => ['$search' => 'Paul']],
395+
],
396+
],
397+
398+
],
399+
];
400+
401+
self::assertEquals($expectedPipeline, $builder->getPipeline());
402+
}
403+
371404
public function testBuilderAppliesFilterAndDiscriminatorWithGeoNearStage(): void
372405
{
373406
$this->dm->getFilterCollection()->enable('testFilter');

tests/Doctrine/ODM/MongoDB/Tests/Functional/FilterTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,4 +334,22 @@ public function testMultipleFiltersOnSameField(): void
334334
*/
335335
self::assertEmpty($this->getUsernamesWithFindAll());
336336
}
337+
338+
public function testFilterOnMatchStageUsingTextOperator(): void
339+
{
340+
$this->dm->getDocumentCollection(User::class)->createIndex(['username' => 'text']);
341+
342+
$this->fc->enable('testFilter');
343+
$testFilter = $this->fc->getFilter('testFilter');
344+
$testFilter->setParameter('class', User::class);
345+
$testFilter->setParameter('field', 'hits');
346+
$testFilter->setParameter('value', 10);
347+
348+
$builder = $this->dm->createAggregationBuilder(User::class)
349+
->match()
350+
->field('username')
351+
->text('John');
352+
353+
self::assertCount(1, $builder->getAggregation()->execute());
354+
}
337355
}

0 commit comments

Comments
 (0)