Skip to content

Step Labels

A step label is a typed handle that names an intermediate traversal result so it can be referenced later in the same query. Step labels are the .NET equivalent of Gremlin's as()/select() modulator pair, but with full type safety.

Two label types are available:

  • StepLabel<T> — a label for values of type T, created explicitly with new StepLabel<T>(). Pass it to .As(label) to mark a position, and to .Select(label) or .Where(… label.Value …) to recall it.
  • StepLabel<TQuery, T> — the same concept but also carries the query type context. This is returned automatically by the continuation overload .As((_, label) => …), which is the idiomatic way to create a label and keep the fluent chain open at the same time.

StepLabel.Value exists only for use in lambda expressions. Calling it at runtime throws NotImplementedException; the Gremlinq expression translator intercepts the member access and emits the corresponding Gremlin select() step instead.

Capturing traversal results

Explicit label with .As(label) and .Select(label)

Create a StepLabel<T> before the traversal, pass it to .As() to capture the current position, then call .Select(label) anywhere downstream to retrieve the captured value.

C#
var airportLabel = new StepLabel<Airport>();

var query = _g
    .V<Airport>()
    .As(airportLabel)
    .Out<Route>()
    .Select(airportLabel);
Inline label with the continuation overload of .As()

The continuation form .As((_, label) => …) provides a StepLabel<TQuery, TElement> whose query-type information is preserved. The resulting label can be passed to .Select(label) to recover the exact query type rather than the untyped IGremlinQuery<T>.

C#
var query = _g
    .V<Airport>()
    .As((__, airportLabel) => __
        .Out<Route>()
        .Select(airportLabel));

Filtering with .Where and a label

Comparing a property against a labeled value

After capturing a vertex with .As(), use label.Value.<Property> inside a .Where() lambda to filter subsequent traversal elements against a property of the labeled element.

C#
var query = _g
    .V<Airport>()
    .As((__, reference) => __
        .V<Airport>()
        .Where(p => p.Code == reference.Value.Code));

Collecting with .Aggregate

Side-effect collection with .Aggregate and .Select

.Aggregate(label) eagerly collects all traversers into a side-effect array stored under label. The traversal itself is unaffected; call .Select(label) later in the same query to materialise the collected array.

C#
var collected = new StepLabel<Airport[]>();

var query = _g
    .V<Airport>()
    .Aggregate(collected)
    .Select(collected);

Real-world patterns

Avoiding return trips (anti-backtracking)

Label the origin vertex, traverse outward two hops, then use .Where with label.Value to exclude any destination that is the same as the origin. This pattern is common in route-finding queries (e.g. AirRoutes) where you want to prevent the traversal from immediately reversing back to where it came from.

C#
var query = _g
    .V<Airport>()
    .As((__, start) => __
        .Out<Route>()           // first hop to an intermediate airport
        .Out<Route>()           // second hop onward
        .OfType<Airport>()      // narrow to Airport vertices
        .Where(p => p != start.Value));  // exclude the origin

Related: Recognized Where Expressions — every filter predicate supported by Gremlinq, including label-value comparisons.