Guide
Projection operations turn a traversal stream into the response shape your application
needs. They are terminal: a projection finishes that traversal entry.
Choose a projection
| Intent | Operation |
|---|---|
| Selected fields | valueMap / value_map |
| Renamed or computed fields | project |
| Correlated row fields | projectBindings / project_bindings |
| Scalar values | id, label, values |
| Aggregates | count, sum, min, max, mean, groupCount |
$id, $label, $from, $to, $distance, and $score
where the preceding operation provides them.
Rename fields
g().n_with_label("User").project(vec![
PropertyProjection::renamed("$id", "user_id"),
PropertyProjection::new("name"),
])
g().nWithLabel("User").project([
PropertyProjection.renamed("$id", "user_id"),
PropertyProjection.new("name"),
])
helix.G().NWithLabel("User").Project(
helix.ProjectPropAs("$id", "user_id"),
helix.ProjectPropAs("name", "name"),
)
g().n_with_label("User").project([
PropertyProjection.renamed("$id", "user_id"),
PropertyProjection.new("name"),
])
{
"request_type": "read",
"query_name": "project_users",
"query": {
"read": {
"entries": [{
"query": {
"name": "users",
"root": {
"project": {
"input": {
"nodes_where": {
"predicate": {
"eq": {
"left": { "property": "$label" },
"right": { "constant": { "string": "User" } }
}
}
}
},
"projections": [
{
"property": {
"source": "$id",
"alias": "user_id"
}
},
{
"property": {
"source": "name",
"alias": "name"
}
}
]
}
}
}
}],
"returns": ["users"]
}
}
}
MATCH (u:User)
RETURN id(u) AS user_id, u.name AS name
Project correlated bindings
projectBindings / project_bindings emits one row per traversal result, reading
values from names captured earlier with bind.
projectDistinctBindings / project_distinct_bindings also removes duplicate
projected tuples.
When alternative branches bind different names, a row carries only the bindings its
own path set. Use coalesce to take the first binding that is present. This request
maps each service to a workload ID, whichever branch found it:
read_batch()
.var_as(
"workloads",
g().n_with_label("Service")
.bind("service")
.out(Some("ROUTES_TO"))
.bind("pod")
.optional(sub().in_(Some("CREATES")).bind("deployment"))
.union(vec![
sub().in_(Some("MANAGES")).bind("owner"),
sub().out(Some("ROUTES_TO")).bind("workload"),
])
.project_distinct_bindings(vec![
BindingProjection::binding("service", "$id", "service_id"),
BindingProjection::coalesce(
vec![
BindingValueRef::binding("deployment", "$id"),
BindingValueRef::binding("owner", "$id"),
BindingValueRef::binding("workload", "$id"),
],
"workload_id",
),
]),
)
.returning(["workloads"]);
readBatch()
.varAs(
"workloads",
g()
.nWithLabel("Service")
.bind("service")
.out("ROUTES_TO")
.bind("pod")
.optional(sub().in("CREATES").bind("deployment"))
.union([sub().in("MANAGES").bind("owner"), sub().out("ROUTES_TO").bind("workload")])
.projectDistinctBindings([
BindingProjection.binding("service", "$id", "service_id"),
BindingProjection.coalesce(
[
BindingProjection.bindingRef("deployment", "$id"),
BindingProjection.bindingRef("owner", "$id"),
BindingProjection.bindingRef("workload", "$id"),
],
"workload_id",
),
]),
)
.returning(["workloads"]);
helix.ReadQuery("service_workloads").
VarAs(
"workloads",
helix.G().
NWithLabel("Service").
Bind("service").
Out("ROUTES_TO").
Bind("pod").
Optional(helix.Sub().In("CREATES").Bind("deployment")).
Union(
helix.Sub().In("MANAGES").Bind("owner"),
helix.Sub().Out("ROUTES_TO").Bind("workload"),
).
ProjectDistinctBindings(
helix.ProjectNamedBinding("service", "$id", "service_id"),
helix.ProjectBindingCoalesce([]helix.BindingValueRef{
helix.NamedBindingValue("deployment", "$id"),
helix.NamedBindingValue("owner", "$id"),
helix.NamedBindingValue("workload", "$id"),
}, "workload_id"),
),
).
Returning("workloads")
(
read_batch()
.var_as(
"workloads",
g()
.n_with_label("Service")
.bind("service")
.out("ROUTES_TO")
.bind("pod")
.optional(sub().in_("CREATES").bind("deployment"))
.union(
[
sub().in_("MANAGES").bind("owner"),
sub().out("ROUTES_TO").bind("workload"),
]
)
.project_distinct_bindings(
[
BindingProjection.binding("service", "$id", "service_id"),
BindingProjection.coalesce(
[
BindingProjection.binding_ref("deployment", "$id"),
BindingProjection.binding_ref("owner", "$id"),
BindingProjection.binding_ref("workload", "$id"),
],
"workload_id",
),
]
),
)
.returning(["workloads"])
)
{
"request_type": "read",
"query_name": "service_workloads",
"query": {
"read": {
"entries": [
{
"query": {
"name": "workloads",
"root": {
"project_bindings": {
"input": {
"union": {
"input": {
"optional": {
"input": {
"bind": {
"input": {
"out": {
"input": {
"bind": {
"input": {
"nodes_where": {
"predicate": {
"eq": {
"left": {
"property": "$label"
},
"right": {
"constant": {
"string": "Service"
}
}
}
}
}
},
"name": "service"
}
},
"label": "ROUTES_TO"
}
},
"name": "pod"
}
},
"traversal": {
"root": {
"bind": {
"input": {
"in": {
"input": "context",
"label": "CREATES"
}
},
"name": "deployment"
}
}
}
}
},
"traversals": [
{
"root": {
"bind": {
"input": {
"in": {
"input": "context",
"label": "MANAGES"
}
},
"name": "owner"
}
}
},
{
"root": {
"bind": {
"input": {
"out": {
"input": "context",
"label": "ROUTES_TO"
}
},
"name": "workload"
}
}
}
]
}
},
"projections": [
{
"property": {
"target": {
"binding": "service"
},
"source": "$id",
"alias": "service_id"
}
},
{
"coalesce": {
"refs": [
{
"target": {
"binding": "deployment"
},
"source": "$id"
},
{
"target": {
"binding": "owner"
},
"source": "$id"
},
{
"target": {
"binding": "workload"
},
"source": "$id"
}
],
"alias": "workload_id"
}
}
],
"distinct": true
}
}
}
}
],
"returns": [
"workloads"
]
}
}
}
MATCH (service:Service)-[:ROUTES_TO]->(pod)
OPTIONAL MATCH (deployment)-[:CREATES]->(pod)
WITH service, deployment, coalesce(deployment, pod) AS current
UNWIND ['MANAGES', 'ROUTES_TO'] AS branch
OPTIONAL MATCH (owner)-[:MANAGES]->(current) WHERE branch = 'MANAGES'
OPTIONAL MATCH (current)-[:ROUTES_TO]->(workload) WHERE branch = 'ROUTES_TO'
WITH service, deployment, owner, workload
WHERE owner IS NOT NULL OR workload IS NOT NULL
RETURN DISTINCT id(service) AS service_id, id(coalesce(deployment, owner, workload)) AS workload_id
UNION (see the
Cypher guide), so the
Cypher tab gives each union branch its own row through UNWIND, runs that branch as
an OPTIONAL MATCH, and drops rows where the branch found nothing.
Aggregate
Appendcount() to a filtered traversal and return that named entry; aggregation runs
inside the transaction instead of materializing every row in the client.
Keep responses small
- Project only fields the caller uses.
- Project
$distancebefore traversing away from a search hit if the score is needed later. - Use aggregates in the engine instead of returning full rows for client-side counting.
- Add
distinctonly when duplicate elimination is semantically required.
Next steps
Bindings and branches
Preserve row-local values across optional and union operations.
Vector search
Create an index, rank vector hits, and preserve distance metadata.