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).
Filter Types
Section titled “Filter Types”Full-text search
Section titled “Full-text search”Searches across both name and description fields (case-insensitive):
{ "search": "quarterly review" }Name filter
Section titled “Name filter”Text filter applied to the thogit’s name:
{ "name": { "regex": "bug" } }Description filter
Section titled “Description filter”Text filter applied to the thogit’s description:
{ "description": { "regex": "TODO" } }Tag presence
Section titled “Tag presence”Check whether a thogit has a specific tag applied. Accepts tag name or tag ID:
{ "has_tag": "Task" }{ "has_tag": "01JQA4N8E3KXYZ..." }Field value predicates
Section titled “Field value predicates”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" } }Logical operators
Section titled “Logical operators”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
Section titled “Operators”Operators determine how a field value is compared. The right-hand side of a dot-notation filter is always an operator expression.
Bare value shorthand
Section titled “Bare value shorthand”Bare values are shorthand for equality:
{ "Task.assignee": "01JQX..." }is equivalent to {"eq": "01JQX..."}.
| Bare Value | Equivalent To |
|---|---|
"text" | {"eq": "text"} |
42 | {"eq": 42} |
true | Boolean equality |
null | {"exists": false} |
Comparison operators
Section titled “Comparison operators”These operators work across multiple types. For strings they compare lexicographically. For numbers and dates they compare numerically/chronologically.
| Operator | Description |
|---|---|
{"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
| Operator | Description |
|---|---|
{"regex": "^reg.*ex$"} | ECMAScript regex match |
Works with: String, Select (matches variant name), MultiSelect (matches any variant name)
Date operators
Section titled “Date operators”Date operators use the same keys as number operators but with date strings:
| Operator | Description |
|---|---|
{"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.
Existence operators
Section titled “Existence operators”| Operator | Description |
|---|---|
{"exists": true} | Field has a non-null value |
{"exists": false} | Field is null or missing |
Bare null is shorthand for {"exists": false}.
Set membership
Section titled “Set membership”{ "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/MultiSelect comparison
Section titled “Select/MultiSelect comparison”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 arrayregex— match variant name against a patternin— match variant name against a set of values
For MultiSelect fields, a match succeeds if any selected variant satisfies the condition.
Progressive Examples
Section titled “Progressive Examples”1. Find all tasks
Section titled “1. Find all tasks”{ "has_tag": "Task" }2. Find tasks that are not done
Section titled “2. Find tasks that are not done”{ "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" } } ]}4. Search within a tag
Section titled “4. Search within a tag”{ "and": [ { "has_tag": "Book" }, { "search": "machine learning" } ]}5. Either/or conditions
Section titled “5. Either/or conditions”{ "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 Traversal
Section titled “Reference Traversal”Reference fields create relationships between thogits. The filter DSL can follow these references using -> notation to filter by properties of the referenced thogit.
Syntax
Section titled “Syntax”SourceTag.ref_field->TargetTag.fieldThe 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
assigneeReference field pointing to a person thogit - A “Person” tag with a
teamString field
Find all tasks assigned to someone on the “Platform” team:
{ "and": [ { "has_tag": "Task" }, { "Task.assignee->Person.team": "Platform" } ]}This filter:
- Looks at each thogit’s
Task.assigneefield (a ULID reference) - Follows the reference to load the target thogit
- Checks that the target thogit’s
Person.teamfield equals “Platform”
Chaining traversals
Section titled “Chaining traversals”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.
Traversal to name/description
Section titled “Traversal to name/description”You can also filter on the referenced thogit’s name or description:
{ "Task.assignee->name": { "regex": "Alice" } }Traversal to has_tag
Section titled “Traversal to has_tag”Check if the referenced thogit has a specific tag:
{ "Task.assignee->has_tag": "Admin" }