Filter operators reference
Every filter operator for record lists, workflow triggers, workflow data steps and search, with what each means, an example and how to combine conditions.
Last updated
Anythink has four places where you filter records, and each has its own syntax. The operators look alike (gt, GT:, >) but are not interchangeable, so check which one you're in.
| Where you filter | Syntax | Use it for |
|---|---|---|
| Record lists | field=GT:5 in the query string |
The record list on the REST API and anythink data list --filter |
| Trigger filters | A JSON tree of and, or, not and conditions |
Stopping an event-triggered workflow from starting |
| Data steps | filter_conditions, a list of field, operator, value |
Read data, Update data and Delete data steps, plus the Condition step |
| Search | fl=status = published |
Full-text search on the REST API, CLI and MCP |
Record list filters#
List filters go in the query string of a record list request. A bare value means equals, and an operator goes in front of the value. REST API reference covers the rest of the list request: paging, sorting and choosing fields.
anythink data list orders --filter 'status=!draft&total=GTE:10'
| Operator | Matches | Example |
|---|---|---|
| (none) | Equal to | status=paid |
! |
Not equal to | status=!paid |
GT: |
Greater than | total=GT:10 |
GTE: |
Greater than or equal to | total=GTE:10 |
LT: |
Less than | total=LT:30 |
LTE: |
Less than or equal to | total=LTE:30 |
C: |
Contains | reference=C:- |
NC: |
Does not contain | reference=NC:A |
SW: |
Starts with | reference=SW:A |
EW: |
Ends with | reference=EW:1 |
IN: |
Is one of a comma-separated list | reference=IN:A-1,B-2 |
Operator prefixes are not case sensitive, so gt:5 and GT:5 do the same. The prefix must come first in the value, with no space before it.
Values and field types
- Text, numbers and booleans (
trueorfalse) are compared as the field's own type. A value that can't be read as that type, such asabcon a number field, is ignored and the filter doesn't apply. - Dates and timestamps take
yyyy-MM-dd,yyyy-MM-ddTHH:mm:ssZor a Unix time in seconds. Times are read as UTC. - Equals and
!compare the whole value and are case sensitive:reference=a-1doesn't matchA-1.C:,NC:,SW:andEW:ignore case. C:,NC:,SW:andEW:also work on number fields, where they match against the number written as text.- Records where the field is empty never match
!,NC:or the comparisons.status=!paidreturns records with another status, not records with no status. - A filter on a field the entity doesn't have is ignored. If a total looks too high, check the field name first.
Combining conditions
- Filters on different fields are joined with AND:
status=paid&total=GT:10. - To put two conditions on one field, separate them with a comma and give each an operator:
total=GTE:6,LT:30means 6 or more and under 30. Both conditions must hold, so this is a range, not a choice. IN:takes a comma-separated list:status=IN:paid,shipped. This is how you ask for one value or another on a single field.- List filters have no OR between different fields and no NOT group. For those, use search filters.
Workflow trigger filters#
A trigger filter decides whether an event starts a workflow. It's checked before a job is created, so a filtered-out event leaves no job. The filter is JSON: a condition has a field, an op and usually a value, and groups wrap conditions. Triggers and scheduling shows how to set one in the Anythink dashboard, the CLI and with an AI assistant.
op |
Matches when | Example |
|---|---|---|
eq |
The field equals value |
{ "field": "status", "op": "eq", "value": "paid" } |
neq |
The field doesn't equal value |
{ "field": "status", "op": "neq", "value": "draft" } |
gt |
The field is greater than value |
{ "field": "total", "op": "gt", "value": 100 } |
gte |
The field is greater than or equal to value |
{ "field": "total", "op": "gte", "value": 100 } |
lt |
The field is less than value |
{ "field": "total", "op": "lt", "value": 100 } |
lte |
The field is less than or equal to value |
{ "field": "total", "op": "lte", "value": 100 } |
in |
The field equals one item in the list value |
{ "field": "status", "op": "in", "value": ["paid", "shipped"] } |
contains |
The field's text contains value, ignoring case |
{ "field": "email", "op": "contains", "value": "@example.com" } |
is_null |
The field is missing or null | { "field": "paid_at", "op": "is_null" } |
is_not_null |
The field has a value | { "field": "paid_at", "op": "is_not_null" } |
changed |
The field's value is different from before the update | { "field": "status", "op": "changed" } |
changed_to |
The field changed, and it now equals value |
{ "field": "status", "op": "changed_to", "value": "paid" } |
Use only these operators. Trigger filters have no sw or ew.
Values and field types
valueis JSON, so it keeps its type:100is a number,"100"is text, andtrueis a boolean. The booleantruedoesn't equal the text"true".- Equals and
neqcompare numbers as numbers, so100equals"100". Text comparison is case sensitive. gt,gte,ltandltecompare as numbers when both sides are numbers, then as dates when both sides are dates, then as text. A null field never matches.inneeds a JSON list invalue.fieldis a top-level field on the record, with no dotted paths.changedandchanged_tocompare the record after the update with its values before. They only match onEntityUpdated.
Combining conditions
Groups nest to any depth.
| Group | Key | Matches when |
|---|---|---|
| All of | and (a list) |
Every item matches. An empty list matches everything. |
| Any of | or (a list) |
At least one item matches. An empty list matches nothing. |
| None of | not (one condition or group) |
The item doesn't match |
The dashboard builder calls these All of these and Any of these. This filter fires when an order becomes paid and is either large or from a trade customer:
{
"and": [
{ "field": "status", "op": "changed_to", "value": "paid" },
{
"or": [
{ "field": "total", "op": "gte", "value": 500 },
{ "field": "customer_type", "op": "eq", "value": "trade" }
]
},
{ "not": { "field": "channel", "op": "eq", "value": "test" } }
]
}
Workflow data step filters#
Read data, Update data and Delete data select records with filter_conditions, a list of conditions. Each condition has a field, an operator and a value. Step types describes each step and its other parameters.
[
{ "field": "status", "operator": "eq", "value": "pending" },
{ "field": "total", "operator": "gte", "value": "100" }
]
operator |
Matches when the field | Example value |
|---|---|---|
eq |
Equals value |
pending |
neq |
Doesn't equal value |
draft |
gt |
Is greater than value |
100 |
gte |
Is greater than or equal to value |
100 |
lt |
Is less than value |
100 |
lte |
Is less than or equal to value |
100 |
in |
Is one of a list | ["paid", "shipped"] or paid,shipped |
contains |
Contains value |
refund |
sw |
Starts with value |
A- |
ew |
Ends with value |
-UK |
Values and field types
valueis always a string, and it can contain templates such as{{ $anythink.trigger.data.id }}. The step reads it as the type of the field, so"100"works on a number field.- Data steps match records the same way record lists do, with
eqmapping to a bare value,neqto!,containstoC:, and so on. That means equals is case sensitive, whilecontains,swandewignore case, and records where the field is empty don't matchneq. - A condition with no
field, or with an operator that isn't in this table, fails the step before anything is read, changed or deleted.
Combining conditions
Every condition in the list must match. There's no OR between data step conditions. To act on two different sets, use two steps, or read with one step and branch with a Condition step.
Condition step#
The Condition step compares values from earlier in the workflow, not records in a table. It uses the same filter_conditions shape, but field is a template path such as $anythink.steps.read_orders.data[0].total, and value can contain templates.
operator |
Matches when | Example value |
|---|---|---|
eq |
The field equals value, ignoring case |
paid |
neq |
The field doesn't equal value, ignoring case |
draft |
gt, gte, lt, lte |
The field compares with value. Numbers compare as numbers; otherwise it compares as text. |
100 |
contains |
The field contains value, ignoring case |
refund |
sw |
The field starts with value, ignoring case |
A- |
ew |
The field ends with value, ignoring case |
-UK |
is_null |
The path is empty or doesn't resolve to anything | (none) |
is_not_null |
The path resolves to a value | (none) |
There's no in operator here. To test against a list, add one eq condition per item and set logical_operator to OR.
Combining conditions: set logical_operator to AND (the default) or OR. It applies to the whole list, with no nesting. When the conditions hold, the workflow follows on success. Otherwise it follows on failure. Use only the operators in this table.
Search filters#
Search filters use Meilisearch's expression syntax and go in the fl parameter. Yours is combined with a restriction to your project, so it can only narrow results. Search records across your entities covers searching, sorting and facets.
anythink search query "*" --entities articles --filter "status = published AND id > 100"
| Operator | Meaning | Example |
|---|---|---|
= |
Equals | status = published |
!= |
Not equal | status != draft |
>, >=, <, <= |
Number comparison | id >= 10 |
TO |
Within a range, both ends included | id 10 TO 50 |
IN [ ] |
Is one of a list | status IN [published, scheduled] |
EXISTS |
The field has a value | subtitle EXISTS |
IS NULL |
The field is null | subtitle IS NULL |
AND |
Both conditions | status = published AND category = news |
OR |
Either condition | status = draft OR status = scheduled |
NOT |
Negates the condition after it | NOT status = draft |
( ) |
Groups conditions | (status = draft OR status = scheduled) AND category = news |
For maps, _geoRadius(lat, lng, distanceInMeters) and _geoBoundingBox([lat, lng], [lat, lng]) filter on a geo field.
Values and field types
- Quote values that contain spaces:
title = "Cold brew notes". URL-encode the whole expression when you build the URL by hand. - Only some fields can be filtered. Filter on a field that isn't in this list and the search returns an error:
- Every field marked Searchable.
- The record's
id,created_atandupdated_at. - Your many-to-one, one-to-one and user fields, searchable or not.
- A geo field, for the geo filters.
- Search filters apply to the search index, which is updated in the background a moment after a record changes.
Combining conditions: join conditions with AND and OR, negate with NOT, and group with brackets. Without brackets, AND binds more tightly than OR, so bracket any mix of the two.
Which one am I using?#
| You're writing | You're in |
|---|---|
total=GT:10 in a URL, --filter on data list |
Record list filters |
"op": "changed_to" in JSON on a workflow's trigger |
Trigger filters |
"operator": "gte" in a step's filter_conditions |
Data step filters, or the Condition step |
fl=status = published, --filter on search query |
Search filters |
Next steps#
- REST API reference for paging, sorting and choosing fields on a list request.
- Triggers and scheduling to add a filter to an event trigger.
- Step types for the Read data, Update data, Delete data and Condition steps.
- Search records across your entities for sorting, facets and searching publicly.