Require
The require argument on a navigation controls whether the parent node is returned based on which of its related nodes are linked through the edge. It turns a navigation from a "return child data if any" expansion into a filter on the parent.
Every nested navigation supports require. It is declared alongside filter, limit, orderBy, etc.
Values
The require argument accepts a small set of JSON forms. All of them normalize to one of three modes: any, some, or none.
| JSON value | Mode | Meaning |
|---|---|---|
(omitted), null, false, "any" | any | No gate (default). The parent is returned regardless of whether any matching child exists. |
true, "some" | some | The parent is returned only if at least one linked child matches. |
"none" | none | The parent is returned only if no linked child matches. |
INFO
The boolean shorthand true exists for historical reasons and is equivalent to "some". Prefer the explicit string form in new queries.
require: "some"
With require: "some" the navigation behaves like an inner-join filter on the parent. The parent is only included in the result when at least one child exists and that child passes the navigation's own filter.
The child branch in the output still reflects what the client asked for — the same set of matching children that was used to gate the parent.
Example: orders that have at least one confirmed delivery
[{
"edge": "orders",
"node": {
"fields": ["orderNumber"],
"navigate": [{
"edge": "deliveries",
"require": "some",
"filter": "deliveryState == 'confirmed'",
"node": {
"fields": ["deliveryNumber"]
}
}]
}
}]Ordering by a nested field
Ordering the parent by a field on a nested many-edge navigation is only possible when that navigation is require: "some". This ensures the value used for sort order is well-defined.
[{
"edge": "orders",
"orderBy": "customer.name asc",
"node": {
"fields": ["orderNumber"],
"navigate": [{
"edge": "customer",
"alias": "customer",
"require": "some",
"node": {
"fields": ["name"]
}
}]
}
}]If you attempt to order by a nested field without require: "some" on that navigation, the query is rejected with:
Ordering by '<alias>' not allowed. To allow order, mark navigation with require='some'.require: "none"
With require: "none" the navigation behaves like an anti-join. The parent is only included when no matching child exists. This is the mechanism for "find parents that lack a certain relation".
Because a none navigation never produces output, several other navigation options are incompatible with it and will be rejected during validation:
| Option | Allowed under none? |
|---|---|
fields | ❌ A none navigation produces no output. |
orderBy | ❌ No rows to order. |
phrase | ❌ No rows to search. |
limit | ❌ No rows to limit. |
after / before | ❌ No cursor applies. |
count | ❌ Nothing to count. |
filter | ✅ Defines what counts as a "matching" child. |
Nested navigate | ✅ But every nested navigation must itself specify require (see below). |
Nested navigations under none
A navigation with require: "none" may contain nested navigations, but every one of them must declare require explicitly as "some" or "none". The default any is not allowed under none — it would produce no output anyway, and the explicit form makes the intent clear.
The nested navigation contributes to the definition of "matching child" — the anti-join searches for children that pass the filter and satisfy their own nested requires. A child only qualifies for the anti-join if all of these hold.
Example: orders with no cancelled delivery
[{
"edge": "orders",
"node": {
"fields": ["orderNumber"],
"navigate": [{
"edge": "deliveries",
"require": "none",
"filter": "deliveryState == 'cancelled'"
}]
}
}]Example: orders that have no payment with a successful authorization
This shows nested requires under a none: "give me orders that do not have any payment which has at least one successful authorization".
[{
"edge": "orders",
"node": {
"fields": ["orderNumber"],
"navigate": [{
"edge": "payments",
"require": "none",
"navigate": [{
"edge": "authorizations",
"require": "some",
"filter": "authorizationState == 'successful'"
}]
}]
}
}]require: "any" (default)
any is the default and means no gating: the parent is returned regardless of the children, and the navigation branch is still emitted in the output — as an object or array, depending on cardinality, and as null or [] when no children are linked.
Use any (or simply leave require out) whenever you want data expansion without affecting which parents are returned.
Cardinality and edge direction
require works on edges of any cardinality, but the semantics differ slightly:
- Many-edges (
single-to-many,many-to-many)some— the parent is kept if at least one linked row matches.none— the parent is kept only if no linked row matches.
- Single-edges (
single-to-single,many-to-single)some— the linked record must exist and match.none— the linked record must either not exist or not match.
INFO
On single-edges, filter is only allowed when require is "some" or "none". A filter on a single edge without require is rejected:
Filter is not allowed on single optional edges at '<path>'Add require: "some" to apply the filter as a parent filter, or require: "none" to invert it.
Interaction with filter
filter and require on the same navigation cooperate:
filterdecides what counts as a matching child.requiredecides what the existence of matching children means for the parent.
A filter without require on a many-edge simply restricts the children in the output — the parent is always returned. Pair it with require: "some" to also remove parents that have no matching child.