Aggregation
Count, sum, average, and group results using aggregate functions.
Aggregate functions compute summary values over matched results. They appear in the return block and automatically group by any non-aggregated return keys.
Aggregate functions
| Function | Description |
|---|---|
count($var) | Number of matched bindings |
sum($var.prop) | Sum of a numeric property |
avg($var.prop) | Arithmetic mean of a numeric property |
min($var.prop) | Minimum value |
max($var.prop) | Maximum value |
count(*) is not supported. Always pass a bound variable.
Count
Count the number of matched nodes:
query total_people() {
match {
$p: Person
}
return { count($p) as total }
}[
{ "total": 847 }
]Sum and average
Compute totals and means over numeric properties:
query age_stats() {
match {
$p: Person
}
return {
count($p) as total,
sum($p.age) as total_age,
avg($p.age) as average_age
}
}Min and max
Find the extreme values of a property:
query age_range() {
match {
$p: Person
}
return {
min($p.age) as youngest,
max($p.age) as oldest
}
}Aliasing with as
Every aggregate should be aliased with as to give the output column a readable name:
query company_headcount() {
match {
$p: Person
$p worksAt $c
}
return { $c.name, count($p) as headcount }
}Grouping
When you mix plain properties and aggregates in return, the plain properties
become grouping keys. Results are grouped by those keys automatically. Each
non-aggregate expression in return must be either a bound variable
($c) or a direct property access ($c.name); arbitrary expressions are
rejected by the typechecker. Pull them into the match block first if you
need them.
query employees_per_company() {
match {
$p: Person
$p worksAt $c
}
return { $c.name, count($p) as employees }
}[
{ "name": "Acme Corp", "employees": 42 },
{ "name": "Globex", "employees": 17 }
]Multiple aggregates
Return several aggregates in a single query:
query company_age_stats() {
match {
$p: Person
$p worksAt $c
}
return {
$c.name,
count($p) as headcount,
avg($p.age) as avg_age,
min($p.age) as youngest,
max($p.age) as oldest
}
}Ordering by aggregated values
Use the aggregate alias in the order block:
query largest_companies() {
match {
$p: Person
$p worksAt $c
}
return { $c.name, count($p) as headcount }
order { headcount desc }
limit 10
}omnigraph read --uri ./graph.omni \
--query queries.gq \
--name largest_companies \
--json[
{ "name": "Acme Corp", "headcount": 42 },
{ "name": "Globex", "headcount": 17 },
{ "name": "Initech", "headcount": 12 }
]