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 source = g
    .UseGremlinServer<Vertex, Edge>(_ => _.AtLocalhost())
    .ConfigureEnvironment(env => env.UseNewtonsoftJson());

var personLabel = new StepLabel<Person>();

var query = source
    .V<Person>()
    .As(personLabel)
    .Out<Edge>()
    .Select(personLabel);
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 source = g
    .UseGremlinServer<Vertex, Edge>(_ => _.AtLocalhost())
    .ConfigureEnvironment(env => env.UseNewtonsoftJson());

var query = source
    .V<Person>()
    .As((__, personLabel) => __
        .Out<Edge>()
        .Select(personLabel));

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 source = g
    .UseGremlinServer<Vertex, Edge>(_ => _.AtLocalhost())
    .ConfigureEnvironment(env => env.UseNewtonsoftJson());

var query = source
    .V<Person>()
    .As((__, reference) => __
        .V<Person>()
        .Where(p => p.Name == reference.Value.Name));

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 source = g
    .UseGremlinServer<Vertex, Edge>(_ => _.AtLocalhost())
    .ConfigureEnvironment(env => env.UseNewtonsoftJson());

var collected = new StepLabel<Person[]>();

var query = source
    .V<Person>()
    .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 source = g
    .UseGremlinServer<Vertex, Edge>(_ => _.AtLocalhost())
    .ConfigureEnvironment(env => env.UseNewtonsoftJson());

var query = source
    .V<Person>()
    .As((__, start) => __
        .Out<Edge>()            // first hop to an intermediate vertex
        .Out<Edge>()            // second hop onward
        .OfType<Person>()       // narrow to Person vertices
        .Where(p => p != start.Value));  // exclude the origin

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