For the complete documentation index optimized for AI agents, see llms.txt.Up to this point every example has ended with
.valueMap([...]) to ship a few
properties back to the caller. This page covers the full set of terminal projections:
how to shape the output, compute derived values, and aggregate the stream.
A terminal step (.count, .values, .project, …) ends the chain and produces a
result rather than another stream. TypeScript and Rust block further chaining at
compile time; Go reports it at serialization (Validate, MarshalRequest, or Client.Exec).
Scalar terminals: .count, .exists, .id, .label
The smallest terminals collapse the whole stream into a single value.
| Step | Returns |
|---|---|
.count() | Number of items in the stream. |
.exists() | true if the stream is non-empty, false otherwise. |
.id() | Stream of $id values, one per item. |
.label() | Stream of $label values, one per item. |
.id() and .label() are usually most useful followed by another binding via
.varAs(...), or as input to .project(...).
.values(...) and .valueMap(...)
When you want a few properties from each item:
.values([prop, ...])— emits an array of arrays, one inner array per item, with the properties in the requested order. No keys, only positional values..valueMap([prop, ...])— emits an array of objects keyed by property name. Passnull(or omit the argument) for “every property”.
valueMap is the default choice for service-facing routes; values is handy when
the caller does its own positional decoding.
$id, $label, $from, $to, $distance, and $score are virtual fields: they are
always available even though they are not declared on your schema. $from/$to
appear on edge streams; $distance/$score appear on ranked vector / text hits.
Filtered values(...) and valueMap(...) also accept dotted paths into object
properties, such as metadata.externalID. valueMap(null) returns stored
top-level properties as-is and does not flatten nested objects. When you request a
dotted path explicitly, the returned object is keyed by the requested source
string unless you rename it with project(...).
.project(...) with renames and expressions
project([...]) is the most flexible terminal — it accepts a list of items, each one
either:
PropertyProjection.new(prop)— emitpropunder its own name.PropertyProjection.renamed(source, alias)— emitsourceunder a different key.ExprProjection.new(alias, expr)— emit a computed expression underalias.
$id, return a different name
than the schema’s, or compute a derived field.
PropertyProjection and Expr.prop(...) use the same property lookup rules as
filters. This means nested object fields can be projected and renamed:
.orderBy("metadata.score", Order.Desc), but they are not backed by secondary
indexes in V1.
A typical project call mixes plain property pulls with one or two renames:
Project is a bare object with source / alias (for
PropertyProjection) or alias / expr (for ExprProjection). There is no enum
tag around them — the Projection enum is untagged on the wire.
Expressions for ExprProjection
Expr is a small arithmetic-and-conditionals algebra:
- Sources:
Expr.prop(name),Expr.val(value),Expr.id(),Expr.timestamp(),Expr.datetime(),Expr.param(name). - Arithmetic:
.add(other),.sub(other),.mul(other),.div(other),.modulo(other),.neg(). - Branching:
Expr.case([[predicate, expr], ...], elseExpr).
"unknown" when the tier property is null:
Expr.timestamp() (server epoch millis) or Expr.datetime() (typed datetime) on
one side of a Predicate.compare(left, CompareOp.*, right). Arithmetic on Expr
returns another Expr, so you can chain Expr.timestamp().sub(Expr.val(30 * 86_400 * 1000))
to compute a cut-off server-side.
Edge property output
For edge streams,.edgeProperties() emits each edge as an object with all of its
properties plus the virtual $id, $label, $from, $to, $distance, and
$score fields when those fields are present on the current ranked edge stream.
Aggregations: .group, .groupCount, .aggregateBy
For grouped counts and aggregate statistics:
.group(prop)— bucket the stream byprop, emit{groupValue: [items...]}..groupCount(prop)— bucket and count, emit{groupValue: count}..aggregateBy(AggregateFunction.*, prop)— apply a reducer to one property:Count,Sum,Min,Max,Mean.
AggregateFunction values are serialized as strings: "Count", "Sum", "Min",
"Max", "Mean".
Next Steps
Mutations
writeBatch, addN, addE, setProperty, drop — and using results inside the same batch.Vector and text search
vectorSearchNodes, textSearchNodes, projecting $distance, follow-on traversal.