Traversal
Follow edges through the graph with single-hop, multi-hop, reverse, and negated traversal patterns.
Traversal patterns let you follow edges between nodes. You write them as $source edgeType $target inside the match block.
Single-hop traversal
Match a direct edge between two nodes:
query friends_of($name: String) {
match {
$p: Person { name: $name }
$p knows $f
}
return { $f.name }
}This finds every Person connected to $p by a Knows edge.
Reverse traversal
Swap the variable positions to traverse in the opposite direction:
query who_knows($name: String) {
match {
$target: Person { name: $name }
$source knows $target
}
return { $source.name }
}This finds people who have a Knows edge pointing to $target.
Sequential multi-hop
Chain multiple traversal patterns to follow paths through the graph:
query friends_of_friends($name: String) {
match {
$p: Person { name: $name }
$p knows $friend
$friend knows $fof
$fof.name != $name
}
return { $fof.name }
}Each pattern adds one hop. Variables bind at each step, so you can filter or return intermediate nodes.
Bounded hops
Use {min, max} syntax to specify a range of hops:
query reachable($name: String) {
match {
$p: Person { name: $name }
$p knows{1,3} $reachable
}
return { $reachable.name }
}This finds all Person nodes reachable from $p within 1 to 3 Knows hops.
| Syntax | Meaning |
|---|---|
edge{2} | Exactly 2 hops |
edge{1,3} | Between 1 and 3 hops |
edge{2,} | 2 or more hops |
Chained traversals across types
Traverse through different edge types in sequence:
query colleagues($name: String) {
match {
$p: Person { name: $name }
$p worksAt $c
$colleague worksAt $c
$colleague.name != $name
}
return { $colleague.name, $c.name }
}Wildcard variables
Use $_ when you need to traverse an edge but don't care about the target:
query has_connections() {
match {
$p: Person
$p knows $_
}
return { $p.name }
}This returns people who have at least one Knows edge, without binding the other end.
Negation (anti-join)
Use not { } to exclude patterns. A result is returned only if the negated pattern has no matches:
query loners() {
match {
$p: Person
not {
$p knows $_
}
}
return { $p.name }
}This finds people with no outgoing Knows edges.
Negation blocks can contain full patterns including traversals and predicates:
query not_at_company($company: String) {
match {
$p: Person
not {
$c: Company { name: $company }
$p worksAt $c
}
}
return { $p.name }
}omnigraph read ./repo.omni \
--query queries.gq \
--name loners \
--json[
{ "name": "Dave" }
]