Skip to content

Commit 2ba7d7a

Browse files
committed
[TASK] Add documentation for aggregations
1 parent 8d9cd7b commit 2ba7d7a

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,121 @@ prototype(Acme.Blog:SingleTag) < prototype(TYPO3.Neos:Template) {
229229
}
230230
```
231231

232+
## Aggregations
233+
234+
Aggregation is an easy way to aggregate your node data in different ways. ElasticSearch provides a couple of different types of
235+
aggregations. Check `https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html` for more
236+
info about aggregations. You can use them to get some simple aggregations like min, max or average values for
237+
your node data. Aggregations also allows you to build a complex filter for e.g. a product search or statistics.
238+
239+
**Aggregation methods**
240+
Right now there are two methods implemented. One generic `aggregation` function that allows you to add any kind of
241+
aggregation definition and a pre-configured `fieldBasedAggregation`. Both methods can be added to your TS search query.
242+
You can nest aggregations by providing a parent name.
243+
244+
* `aggregation($name, array $aggregationDefinition, $parentPath = NULL)` -- generic method to add a $aggregationDefinition under a path $parentPath with the name $name
245+
* `fieldBasedAggregation($name, $field, $type = "terms", $parentPath = NULL)` -- adds a simple filed based Aggregation of type $type with name $name under path $parentPath. Used for simple aggregations like sum, avg, min, max or terms
246+
247+
248+
### Examples
249+
#### Add a average aggregation
250+
To add an average aggregation you can use the fieldBasedAggregation. This snippet would add an average aggregation for
251+
a property price:
252+
```
253+
nodes = ${Search.query(site)...fieldBasedAggregation("avgprice", "price", "avg").execute()}
254+
```
255+
Now you can access your aggregations inside your fluid template with
256+
```
257+
{nodes.aggregations}
258+
```
259+
260+
#### Create a nested aggregation
261+
In this scenario you could have a node that represents a product with the properties price and color. If you would like
262+
to know the average price for all your colors you just nest an aggregation in your TypoScript:
263+
```
264+
nodes = ${Search.query(site)...fieldBasedAggregation("colors", "color").fieldBasedAggregation("avgprice", "price", "avg", "colors").execute()}
265+
```
266+
The first `fieldBasedAggregation` will add a simple terms aggregation (https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html)
267+
with the name colors. So all different colors of your nodetype will be listed here.
268+
The second `fieldBasedAggregation` will add another sub-aggregation named avgprice below your colors-aggregation.
269+
270+
You can nest even more aggregations like this:
271+
```
272+
fieldBasedAggregation("anotherAggregation", "field", "avg", "colors.avgprice")
273+
```
274+
275+
#### Add a custom aggregation
276+
To add a custom aggregation you can use the `aggregation()` method. All you have to do is to provide an array with your
277+
aggregation definition. This example would do the same as the fieldBasedAggregation would do for you:
278+
```
279+
aggregationDefinition = TYPO3.TypoScript:RawArray {
280+
terms = TYPO3.TypoScript:RawArray {
281+
field = "color"
282+
}
283+
}
284+
nodes = ${Search.query(site)...aggregation("color", this.aggregationDefinition).execute()}
285+
```
286+
287+
#### Product filter
288+
This is a more complex scenario. With this snippet we will create a full product filter based on your selected Nodes. Imagine
289+
an NodeTye ProductList with an property `products`. This property contains a comma separated list of sku's. This could also
290+
be a reference on other products.
291+
292+
```
293+
prototype(Vendor.Name:FilteredProductList) < prototype(TYPO3.Neos:Content)
294+
prototype(Vendor.Name:FilteredProductList) {
295+
296+
// Create SearchFilter for products
297+
searchFilter = TYPO3.TypoScript:RawArray {
298+
sku = ${String.split(q(node).property("products"), ",")}
299+
}
300+
301+
# Search for all products that matches your queryFilter and add aggregations
302+
filter = ${Search.query(site).nodeType("Vendor.Name:Product").queryFilterMultiple(this.searchFilter, "must").fieldBasedAggregation("color", "color").fieldBasedAggregation("size", "size").execute()}
303+
304+
# Add more filter if get/post params are set
305+
searchFilter.color = ${request.arguments.color}
306+
searchFilter.color.@if.onlyRenderWhenFilterColorIsSet = ${request.arguments.color != ""}
307+
searchFilter.size = ${request.arguments.size}
308+
searchFilter.size.@if.onlyRenderWhenFilterSizeIsSet = ${request.arguments.size != ""}
309+
310+
# filter your products
311+
products = ${Search.query(site).nodeType("Vendor.Name:Product").queryFilterMultiple(this.searchFilter, "must").execute()}
312+
313+
# don't cache this element
314+
@cache {
315+
mode = 'uncached'
316+
context {
317+
1 = 'node'
318+
2 = 'site'
319+
}
320+
}
321+
```
322+
323+
In the first lines we will add a new searchFilter variable and add your selected sku's as a filter. Based on this selection
324+
we will add two aggregations of type terms. You can access the filter in your template with `{filter.aggregation}`. With
325+
this information it is easy to create a form with some select fields with all available options. If you submit the form
326+
just call the same page and add the get parameter color and/or size.
327+
The next lines will parse those parameters and add them to the searchFilter. Based on your selection all products will
328+
be fetched and passed to your template.
329+
330+
331+
**Important notice**
332+
333+
If you do use the terms filter be aware of ElasticSearchs analyze functionality. You might want to disable this for all
334+
your filterable properties like this:
335+
```
336+
'Vendor.Name:Product'
337+
properties:
338+
color:
339+
type: string
340+
defaultValue: ''
341+
search:
342+
elasticSearchMapping:
343+
type: "string"
344+
include_in_all: false
345+
index: 'not_analyzed'
346+
```
232347

233348
## Fulltext Search / Indexing
234349

0 commit comments

Comments
 (0)