Forze uses a shared query DSL for filtering and sorting. The same expression shape is used by document ports (find, find_many, count) and search requests (filters, sorts).
Filter expression shape
A filter expression is one of:
- predicate:
{"$fields": {...}} - conjunction:
{"$and": [expr, ...]} - disjunction:
{"$or": [expr, ...]}
Where expr is recursively one of the three shapes above.
Field shortcuts
Inside "$fields", each field value can use a shortcut or an explicit operator map.
| Field value | Expanded form | Meaning |
|---|---|---|
"active" |
{"$eq": "active"} |
equality |
["a", "b"] |
{"$in": ["a", "b"]} |
membership |
null |
{"$null": true} |
is null |
Example:
filters = {
"$fields": {
"status": "active",
"tags": ["backend", "api"],
"deleted_at": None,
}
}
Operators
Equality
| Operator | Value type | Meaning |
|---|---|---|
$eq |
scalar | equal |
$neq |
scalar | not equal |
Ordering
| Operator | Value type | Meaning |
|---|---|---|
$gt |
numeric/date/datetime | greater than |
$gte |
numeric/date/datetime | greater than or equal |
$lt |
numeric/date/datetime | less than |
$lte |
numeric/date/datetime | less than or equal |
Membership
| Operator | Value type | Meaning |
|---|---|---|
$in |
array | field is in list |
$nin |
array | field is not in list |
Unary checks
| Operator | Value type | Meaning |
|---|---|---|
$null |
bool | true: is null, false: is not null |
$empty |
bool | true: empty array, false: non-empty array |
Set relations (array fields)
| Operator | Value type | Meaning |
|---|---|---|
$superset |
array | field contains all values from list |
$subset |
array | field contains no values outside list |
$overlaps |
array | field intersects list |
$disjoint |
array | field does not intersect list |
Complex examples
Nested AND/OR
filters = {
"$and": [
{"$fields": {"is_deleted": False}},
{
"$or": [
{"$fields": {"priority": {"$gte": 5}}},
{"$fields": {"status": {"$in": ["new", "in_progress"]}}},
]
},
]
}
Range + set relation
filters = {
"$fields": {
"created_at": {"$gte": "2026-01-01T00:00:00Z"},
"labels": {"$overlaps": ["urgent", "customer"]},
}
}
Sorting syntax
Sort expression is a map of field name to direction:
sorts = {
"created_at": "desc",
"id": "asc",
}
Supported directions:
"asc""desc"
If sorts is omitted, adapters default to sorting by id descending.
Where you pass these expressions
Document port usage
doc = ctx.doc_read(project_spec)
rows, total = await doc.find_many(
filters=filters,
sorts=sorts,
limit=20,
offset=0,
)
Search request usage
search = ctx.search(project_search_spec)
hits, total = await search.search(
query="roadmap",
filters=filters,
sorts=sorts,
limit=20,
offset=0,
)
Validation rules
- A field operator map cannot be empty.
- Unknown operators fail validation.
- Operator values must match expected types.
{"$null": true}cannot be combined with other operators on the same field.{"$empty": true}cannot be combined with other operators on the same field.
Backend notes
- Semantics are shared, but rendering is backend-specific (Postgres vs Mongo).
- For Postgres array columns, shortcuts are normalized:
$eqmay behave as array superset$inmay behave as overlaps$ninmay behave as disjoint- In Mongo renderer defaults,
$null: truematches both explicitnulland missing fields.