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.

bash
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 (true or false) are compared as the field's own type. A value that can't be read as that type, such as abc on a number field, is ignored and the filter doesn't apply.
  • Dates and timestamps take yyyy-MM-dd, yyyy-MM-ddTHH:mm:ssZ or a Unix time in seconds. Times are read as UTC.
  • Equals and ! compare the whole value and are case sensitive: reference=a-1 doesn't match A-1. C:, NC:, SW: and EW: ignore case.
  • C:, NC:, SW: and EW: 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=!paid returns 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:30 means 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

  • value is JSON, so it keeps its type: 100 is a number, "100" is text, and true is a boolean. The boolean true doesn't equal the text "true".
  • Equals and neq compare numbers as numbers, so 100 equals "100". Text comparison is case sensitive.
  • gt, gte, lt and lte compare as numbers when both sides are numbers, then as dates when both sides are dates, then as text. A null field never matches.
  • in needs a JSON list in value. field is a top-level field on the record, with no dotted paths.
  • changed and changed_to compare the record after the update with its values before. They only match on EntityUpdated.

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:

json
{
  "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.

json
[
  { "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

  • value is 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 eq mapping to a bare value, neq to !, contains to C:, and so on. That means equals is case sensitive, while contains, sw and ew ignore case, and records where the field is empty don't match neq.
  • 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.

bash
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_at and updated_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#