Query nodes by their properties¶
The where predicate filters nodes by exact values in their properties
or data JSONB — a structured WHERE clause over the graph. It works on both
GraphQL findNodes and MCP hadron_find_nodes, and it composes with
keyword, vector, hybrid, and regex retrieval as well as the no-query browse.
This guide builds up from a single leaf to a tree, adds typed casts, facets by
collection, and composes where with a search query. For the full grammar see
Structured storage and queries.
The shape of a predicate¶
A predicate is either a branch or a leaf:
- Branch — exactly one of
and/or/not. - Leaf — a
path(array of object keys into the column) plus exactly one operator (eq,ne,in,lt,lte,gt,gte,between,exists,contains).
Two optional leaf modifiers: field picks the column (properties, the
default, or data), and as types the value before comparison (text, the
default, or number / datetime / boolean).
1. A single eq leaf¶
Find nodes whose stage property equals series-a. On MCP:
{
"tool": "hadron_find_nodes",
"memoryUrn": "acme.com:market",
"query": "*",
"where": { "path": ["stage"], "eq": "series-a" }
}
On MCP, query is required — pass "*" (or "") for survey mode: no
ranking, just the nodes the where predicate keeps. The GraphQL equivalent
passes where inside filter and can omit the query entirely:
query SeriesA {
findNodes(
filter: {
memoryIds: ["<memoryId>"]
where: { path: ["stage"], eq: "series-a" }
}
) {
hits { node { loc name properties } }
total
}
}
With survey mode (query: "*") — or, on GraphQL, no query at all — this is an
unscored browse: a filtered list, score null on each hit.
2. Combine leaves with and / or / not¶
Wrap leaves in a branch. Series-A or series-B competitors, excluding public ones:
{
"and": [
{ "or": [
{ "path": ["stage"], "eq": "series-a" },
{ "path": ["stage"], "eq": "series-b" }
] },
{ "not": { "path": ["isPublic"], "as": "boolean", "eq": true } }
]
}
The or above is equivalent to a single in leaf, which is shorter:
3. Cast for numbers and dates¶
Values in JSONB compare as text by default — lexical, not numeric or
chronological. For ordered comparisons on numbers and dates, set as.
Competitors that raised more than 10 million:
A temporal "in the last N days" query — last round on or after a cutoff you compute client-side (here, 90 days back):
number and datetime casts route through DB guard functions: a value that
can't be parsed drops the row rather than raising an error. So a malformed
lastRoundAt simply won't match — it never 500s the query.
4. Facet by collection with objectType¶
If the memory mixes collections, narrow to one with the objectType facet
(alongside where, not inside it). On MCP it's a top-level argument:
{
"tool": "hadron_find_nodes",
"memoryUrn": "acme.com:market",
"query": "*",
"objectType": "competitor",
"where": { "path": ["stage"], "eq": "series-a" }
}
On GraphQL it's filter.objectType:
findNodes(filter: {
objectType: "competitor"
where: { path: ["stage"], eq: "series-a" }
}) { hits { node { loc name } } }
5. Compose where with a search query¶
where filters, then the chosen mode ranks the survivors. Add a
query and mode to combine structured filtering with keyword or semantic
retrieval — "the most relevant series-A competitors to developer tooling":
{
"tool": "hadron_find_nodes",
"memoryUrn": "acme.com:market",
"query": "developer tooling",
"mode": "vector",
"objectType": "competitor",
"where": { "path": ["stage"], "eq": "series-a" }
}
How composition works by mode:
- Keyword / regex / browse — the predicate is applied in-query.
- Vector / hybrid — the predicate post-filters the ranked candidate set; the semantic rank order is preserved among survivors.
Caps and error behavior¶
The predicate is bounded: depth ≤ 4, ≤ 32 leaves total, path ≤ 8
segments. A malformed or oversized tree — a branch with more than one of
and/or/not, a leaf with more than one operator, or exceeding a cap — is
rejected as BAD_USER_INPUT. (Unparseable values under a number/datetime
cast are not errors; they just drop the row.)
Next steps¶
- Sort results by a property value — order the
filtered set with
sortProperty(GraphQL). - Give a memory a structured schema — declare the fields you're querying.
- Structured storage and queries — the full operator and cast reference.