Skip to content

Commit 13be186

Browse files
author
fedorf4
committed
add reverse nested agg
1 parent 2ed83f1 commit 13be186

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Aggregating\Bucket;
4+
5+
use Ensi\LaravelElasticQuery\Aggregating\AggregationCollection;
6+
use Ensi\LaravelElasticQuery\Contracts\Aggregation;
7+
use Webmozart\Assert\Assert;
8+
9+
class ReverseNestedAggregation implements Aggregation
10+
{
11+
public function __construct(
12+
private string $name,
13+
private AggregationCollection $children
14+
) {
15+
Assert::stringNotEmpty(trim($name));
16+
}
17+
18+
public function name(): string
19+
{
20+
return $this->name;
21+
}
22+
23+
public function toDSL(): array
24+
{
25+
return [$this->name => [
26+
'reverse_nested' => new \stdClass(),
27+
'aggs' => $this->children->toDSL(),
28+
]];
29+
}
30+
31+
public function parseResults(array $response): array
32+
{
33+
return $this->children
34+
->parseResults($response[$this->name] ?? [])
35+
->all();
36+
}
37+
}

src/Concerns/ConstructsAggregations.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Ensi\LaravelElasticQuery\Aggregating\Bucket\FilterAggregation;
88
use Ensi\LaravelElasticQuery\Aggregating\Bucket\FiltersAggregation;
99
use Ensi\LaravelElasticQuery\Aggregating\Bucket\NestedAggregation;
10+
use Ensi\LaravelElasticQuery\Aggregating\Bucket\ReverseNestedAggregation;
1011
use Ensi\LaravelElasticQuery\Aggregating\Bucket\TermsAggregation;
1112
use Ensi\LaravelElasticQuery\Aggregating\CompositeAggregationBuilder;
1213
use Ensi\LaravelElasticQuery\Aggregating\FiltersCollection;
@@ -132,6 +133,21 @@ public function nested(string $path, Closure $callback): static
132133
return $this;
133134
}
134135

136+
public function reverseNested(string $name, Closure $callback): static
137+
{
138+
$builder = $this->createCompositeBuilder("{$name}_builder");
139+
140+
/** @var AggregationCollection $aggs */
141+
$aggs = tap($builder, $callback)->build();
142+
143+
if (!$aggs->isEmpty()) {
144+
$reverseNested = new ReverseNestedAggregation($name, $aggs);
145+
$this->aggregations->merge(AggregationCollection::fromAggregation($reverseNested));
146+
}
147+
148+
return $this;
149+
}
150+
135151
protected function name(): string
136152
{
137153
return '';

src/Contracts/AggregationsBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,6 @@ public function count(string $path, string $field): static;
2828
public function script(string $name, string $aggregationType, string $source, array $params = [], string $lang = ScriptLang::PAINLESS): static;
2929

3030
public function nested(string $path, Closure $callback): static;
31+
32+
public function reverseNested(string $name, Closure $callback): static
3133
}

tests/IntegrationTests/AggregationQueryIntegrationTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Ensi\LaravelElasticQuery\Aggregating\AggregationCollection;
44
use Ensi\LaravelElasticQuery\Aggregating\Bucket;
5+
use Ensi\LaravelElasticQuery\Aggregating\BucketCollection;
56
use Ensi\LaravelElasticQuery\Aggregating\FiltersCollection;
67
use Ensi\LaravelElasticQuery\Aggregating\Metrics\MinMaxScoreAggregation;
78
use Ensi\LaravelElasticQuery\Aggregating\Metrics\ScriptAggregation;
@@ -262,3 +263,26 @@
262263
$scores,
263264
);
264265
});
266+
267+
test('reverse nested aggregation query', function () {
268+
/** @var IntegrationTestCase $this */
269+
270+
$results = ProductsIndex::aggregate()
271+
->nested('offers', function ($builder) {
272+
$builder->terms('offer_prices', 'offers.price', 5)
273+
->reverseNested('root_stats', function ($reverseBuilder) {
274+
$reverseBuilder->cardinality('unique_products', 'product_id')
275+
->count('total_products', 'product_id');
276+
});
277+
})
278+
->get();
279+
280+
$prices = $results->get('offer_prices');
281+
282+
expect($prices)->toBeInstanceOf(BucketCollection::class);
283+
284+
foreach ($prices as $bucket) {
285+
expect($bucket->getCompositeValue('unique_products'))->toBeGreaterThan(0);
286+
expect($bucket->getCompositeValue('total_products'))->toBeGreaterThan(0);
287+
}
288+
});

0 commit comments

Comments
 (0)