Filtering
A FilterModel exposes its columns as a Map<String, ColumnFilter> — field name → filter.
Each value is one of the sealed ColumnFilter types:
| Type | Column kind | ag-grid filterType |
|---|---|---|
FieldFilter |
text | text |
NumberFieldFilter |
number | number |
DateFieldFilter |
date | date |
| Set | set | set — coming soon |
| Multi | multi-column | multi — coming soon |
Every type mirrors ag-grid’s filter JSON, so a request payload binds straight into it. Text values are matched case-insensitively (the adapter lowercases the query term).
Text filters
A simple text filter is a type + filter value:
{
"name": {
"filterType": "text",
"type": "contains",
"filter": "mac"
}
}
TextFilterType and the query
each produces for value mac on field name:
type |
Matches | Elasticsearch query |
|---|---|---|
contains |
field contains the value | name ~ *mac* |
notContains |
field does not contain the value | NOT name ~ *mac* |
equals |
field equals the value | name = mac |
notEqual |
field differs from the value | NOT name = mac |
startsWith |
field starts with the value | name ~ mac* |
endsWith |
field ends with the value | name ~ *mac |
blank |
field is missing / empty | name does not exist |
notBlank |
field is present | name exists |
A blank/absent filter value drops the condition (it becomes match-all for that column) — except for
blank / notBlank, which need no value.
Number filters
A simple number filter is a type + filter value; inRange adds a filterTo upper bound:
{
"price": {
"filterType": "number",
"type": "inRange",
"filter": 10,
"filterTo": 20
}
}
Values bind to Number (Jackson keeps integers integral). NumberFilterType
for field price:
type |
Matches | Elasticsearch query |
|---|---|---|
equals |
field equals the value | price = 10 |
notEqual |
field differs from the value | NOT price = 10 |
greaterThan |
field greater than the value | price > 10 |
greaterThanOrEqual |
field at least the value | price >= 10 |
lessThan |
field less than the value | price < 10 |
lessThanOrEqual |
field at most the value | price <= 10 |
inRange |
within filter…filterTo |
price in [10 … 20] |
blank |
field is missing / empty | price does not exist |
notBlank |
field is present | price exists |
A missing filter (both bounds for inRange) drops the condition — except for blank / notBlank,
which need no value.
Date filters
Dates are ISO strings (yyyy-MM-dd; anything after the day is ignored). inRange uses both bounds, every
other type uses dateFrom:
{
"createdAt": {
"type": "inRange",
"dateFrom": "2024-01-01",
"dateTo": "2024-12-31"
}
}
DateFilterType for field
createdAt:
type |
Matches | Elasticsearch query |
|---|---|---|
equals |
on that day | createdAt in [day 00:00:00 … 23:59:59] |
notEqual |
not on that day | NOT in [day 00:00:00 … 23:59:59] |
greaterThan |
after that day starts | createdAt > day 00:00:00 |
lessThan |
before that day starts | createdAt < day 00:00:00 |
inRange |
within dateFrom…dateTo |
createdAt in [from 00:00:00 … to 23:59:59] |
equals / inRange expand to a full-day (or full-range) window, so they match regardless of the stored
time-of-day. An unparseable or missing date drops the condition.
Compound filters (AND / OR)
ag-grid’s “two conditions” mode sends an operator plus a conditions array. It works identically for
text, numbers and dates:
{
"name": {
"filterType": "text",
"operator": "OR",
"conditions": [
{
"type": "contains",
"filter": "mac"
},
{
"type": "contains",
"filter": "iphone"
}
]
}
}
The conditions are combined with FilterOperator
AND or OR → name ~ *mac* OR name ~ *iphone*.
Multiple columns
Every active column in the map is combined into the final query. Columns are joined as grouped
sub-queries, so a compound OR/AND on one column keeps its own branches instead of collapsing into a
neighbouring column’s clause:
{
"filterModel": {
"category": {
"filterType": "text",
"type": "equals",
"filter": "electronics"
},
"name": {
"filterType": "text",
"operator": "OR",
"conditions": [
{
"type": "contains",
"filter": "mac"
},
{
"type": "contains",
"filter": "iphone"
}
]
}
}
}
→ category = electronics AND (name ~ *mac* OR name ~ *iphone*).
SeeElasticsearch adapter for why this uses subCriteria rather than and.
Building filters in Java
For tests or server-side filters, use the fluent builders instead of JSON. Every property is optional and
defaults to null:
// contains "mac"
FieldFilter.builder()
.type(TextFilterType.contains)
.filter("mac")
.build();
// name contains "mac" OR "iphone"
FieldFilter.builder()
.operator(FilterOperator.OR)
.conditions(List.of(
FieldFilter.builder().type(TextFilterType.contains).filter("mac").build(),
FieldFilter.builder().type(TextFilterType.contains).filter("iphone").build()))
.build();
// createdAt within 2024
DateFieldFilter.builder()
.type(DateFilterType.inRange)
.dateFrom("2024-01-01")
.dateTo("2024-12-31")
.build();
// price between 10 and 20
NumberFieldFilter.builder()
.type(NumberFilterType.inRange)
.filter(10)
.filterTo(20)
.build();
Coming soon
ag-grid’s set filter (filterType: "set", a values array) and multi-column filter
(filterType: "multi") are not modelled yet. A set filter also unlocks boolean and enum columns, since
ag-grid filters those through the set filter rather than a dedicated boolean filter.