# Aggregations

### Overview

Aggregations compute metrics from your filtered data. Use them to answer questions like "How many errors per service?".

### Syntax

Use the pipe operator `|` to chain a `stats` command after your filters:

```
<filters> | stats <function>(<field>) as <alias>
```

**Single aggregation:**

```
level:error | stats count()
```

**Multiple aggregations:**

```
level:error | stats count() total, count_uniq(workload) services
```

**With grouping:**

```
level:error | stats by (workload) count() errors
```

### Counting Functions

#### count()

Count the number of records.

```
level:error | stats count()
```

#### count\_empty(field)

Count records where a field is empty.

```
* | stats count_empty(error)
```

*Logs with no error field*

#### count\_uniq(field)

Count unique values in a field.

```
* | stats count_uniq(user_id)
```

*Number of unique users*

### Numeric Aggregations

Numeric functions attempt to convert field values to numbers. Non-numeric values are treated as NULL and ignored.

#### avg(field)

Calculate the average (mean) value.

```
* | stats avg(duration_seconds)
```

#### sum(field)

Calculate the total sum.

```
* | stats sum(bytes_sent)
```

#### min(field) and max(field)

Find minimum and maximum values.

```
* | stats min(duration_seconds), max(duration_seconds)
```

#### median(field)

Calculate the median value (50th percentile).

```
* | stats median(bytes)
```

#### quantile(p, field)

Calculate percentiles. Use values between 0 and 1 (0.5 = 50th percentile, 0.95 = 95th percentile).

```
* | stats quantile(0.95, bytes_sent) p95
```

```
* | stats quantile(0.5, bytes_sent) p50, quantile(0.95, bytes_sent) p95, quantile(0.99, bytes_sent) p99
```

#### sum\_len(field)

Sum the length of string values.

```
* | stats sum_len(message)
```

*Total characters in all messages*

### Value Aggregations

#### values(field)

Get all values (with duplicates).

```
level:error | stats values(error_message)
```

*All error messages*

#### uniq\_values(field)

Get unique values (no duplicates).

```
* | stats uniq_values(status_code)
```

*List of all status codes seen*

### Grouping with 'by'

Group results by one or more fields.

#### Single Field Grouping

```
* | stats by (workload) count()
```

```
* | stats by (level) count() as log_count
```

#### Multiple Field Grouping

```
* | stats by (workload, level) count()
```

#### Multiple Functions

```
* | stats by (resource) count(), min(duration_seconds), max(duration_seconds), median(latency)
```

### Post-Aggregation Filtering

Filter results after aggregation.

#### Using filter pipe

```
* | stats by (workload) count() as request_count | filter request_count:>1000
```

*Workloads with more than 1000 requests*

#### Implicit Filtering (Without filter keyword)

```
* | stats by (workload) count() as request_count | request_count:>1000
```

*Same as above, shorter syntax*

### Time-Series Aggregations

**Note:** In groundcover, time bucketing is configured externally through the UI time range selector, not in the query itself.

```
* | stats by (workload) count() as logs_per_minute
```

*Count logs per workload (time interval set in UI)*

```
* | stats by (status_code) count()
```

*Requests per status code over time*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.groundcover.com/use-groundcover/querying-your-groundcover-data/groundcover-query-language/aggregations.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
