Skip to content

Filtering

The filter DSL is a JSON-based query language for finding thogits. Filters compose with logical operators and support everything from full-text search to cross-reference traversal.

All filter examples work with both the REST API (POST /api/thogits/search) and Views (saved filter presets).

Searches across both name and description fields (case-insensitive):

{ "search": "quarterly review" }

Text filter applied to the thogit’s name:

{ "name": { "regex": "bug" } }

Text filter applied to the thogit’s description:

{ "description": { "regex": "TODO" } }

Check whether a thogit has a specific tag applied. Accepts tag name or tag ID:

{ "has_tag": "Task" }
{ "has_tag": "01JQA4N8E3KXYZ..." }

Use dot notation to filter by a tag’s field value. The left side is TagName.fieldName, the right side is an operator:

{ "Task.priority": { "in": [1, 2] } }
{ "Task.due_date": { "lt": "2025-06-01" } }

Combine filters with and, or, and not:

{
"and": [
{ "has_tag": "Task" },
{ "Task.status": { "eq": "Todo" } },
{ "not": { "Task.priority": { "eq": "Low" } } }
]
}

and and or require at least 2 conditions. not wraps a single filter.

Operators determine how a field value is compared. The right-hand side of a dot-notation filter is always an operator expression.

Bare values are shorthand for equality:

{ "Task.assignee": "01JQX..." }

is equivalent to {"eq": "01JQX..."}.

Bare ValueEquivalent To
"text"{"eq": "text"}
42{"eq": 42}
trueBoolean equality
null{"exists": false}

These operators work across multiple types. For strings they compare lexicographically. For numbers and dates they compare numerically/chronologically.

OperatorDescription
{"eq": value}Equal
{"neq": value}Not equal
{"gt": value}Greater than
{"gte": value}Greater than or equal
{"lt": value}Less than
{"lte": value}Less than or equal

Works with: String (lexicographic), Number, Date

OperatorDescription
{"regex": "^reg.*ex$"}ECMAScript regex match

Works with: String, Select (matches variant name), MultiSelect (matches any variant name)

Date operators use the same keys as number operators but with date strings:

OperatorDescription
{"eq": "2025-04-15"}Exact date match
{"gt": "2025-01-01"}After a date
{"lte": "2025-12-31T23:59:59"}On or before a datetime

Both YYYY-MM-DD and YYYY-MM-DDTHH:MM:SS formats are supported. Dates are auto-detected — if a string parses as a date, it’s treated as a date comparison.

OperatorDescription
{"exists": true}Field has a non-null value
{"exists": false}Field is null or missing

Bare null is shorthand for {"exists": false}.

{ "Task.priority": { "in": [1, 2, 3] } }

Matches if the field value is any of the listed values. Works with Select (matches variant name) and MultiSelect (matches if any variant is in the set) fields too.

Select and MultiSelect fields use the standard comparison operators. The behavior depends on the operator:

  • eq / neq — match by variant name (e.g., {"eq": "Done"})
  • gt / gte / lt / lte — compare by ordinal position in the schema’s variants array
  • regex — match variant name against a pattern
  • in — match variant name against a set of values

For MultiSelect fields, a match succeeds if any selected variant satisfies the condition.

{ "has_tag": "Task" }
{
"and": [
{ "has_tag": "Task" },
{ "not": { "Task.status": { "eq": "Done" } } }
]
}

3. Find high-priority tasks due this month

Section titled “3. Find high-priority tasks due this month”
{
"and": [
{ "has_tag": "Task" },
{ "Task.priority": { "in": [1, 2] } },
{ "Task.due_date": { "gte": "2025-04-01" } },
{ "Task.due_date": { "lte": "2025-04-30" } }
]
}
{
"and": [
{ "has_tag": "Book" },
{ "search": "machine learning" }
]
}
{
"or": [
{ "Task.status": { "eq": "Blocked" } },
{ "Task.status": { "eq": "Critical" } }
]
}

6. Tasks whose status is at least InProgress

Section titled “6. Tasks whose status is at least InProgress”
{
"and": [
{ "has_tag": "Task" },
{ "Task.status": { "gte": "InProgress" } }
]
}

Reference fields create relationships between thogits. The filter DSL can follow these references using -> notation to filter by properties of the referenced thogit.

SourceTag.ref_field->TargetTag.field

The left side (SourceTag.ref_field) must be a Reference field. The right side is a filter applied to the thogit that the reference points to.

Example: Tasks assigned to a specific team

Section titled “Example: Tasks assigned to a specific team”

Suppose you have:

  • A “Task” tag with an assignee Reference field pointing to a person thogit
  • A “Person” tag with a team String field

Find all tasks assigned to someone on the “Platform” team:

{
"and": [
{ "has_tag": "Task" },
{ "Task.assignee->Person.team": "Platform" }
]
}

This filter:

  1. Looks at each thogit’s Task.assignee field (a ULID reference)
  2. Follows the reference to load the target thogit
  3. Checks that the target thogit’s Person.team field equals “Platform”

You can chain multiple hops with ->:

{ "Task.project_ref->Project.owner_ref->Person.team": "Platform" }

This follows Task.project_ref to a project thogit, then Project.owner_ref to a person thogit, and checks their team. The maximum traversal depth is 5 hops.

You can also filter on the referenced thogit’s name or description:

{ "Task.assignee->name": { "regex": "Alice" } }

Check if the referenced thogit has a specific tag:

{ "Task.assignee->has_tag": "Admin" }