# Aggregating functions

An aggregating function performs a calculation over a set of values, returning a single value. Aggregation can be computed over all the matching paths, or it can be further divided by introducing grouping keys.

 To learn more about how Cypher® handles aggregations performed on zero rows, refer to Neo4j Knowledge Base → Understanding aggregations on zero rows.

## Example graph

The following graph is used for the examples below: To recreate the graph, run the following query against an empty Neo4j database:

``````CREATE
(keanu:Person {name: 'Keanu Reeves', age: 58}),
(liam:Person {name: 'Liam Neeson', age: 70}),
(carrie:Person {name: 'Carrie Anne Moss', age: 55}),
(guy:Person {name: 'Guy Pearce', age: 55}),
(kathryn:Person {name: 'Kathryn Bigelow', age: 71}),
(speed:Movie {title: 'Speed'}),
(keanu)-[:ACTED_IN]->(speed),
(keanu)-[:KNOWS]->(carrie),
(keanu)-[:KNOWS]->(liam),
(keanu)-[:KNOWS]->(kathryn),
(carrie)-[:KNOWS]->(guy),
(liam)-[:KNOWS]->(guy)``````

## avg() - Numeric values

The function `avg()` returns the average of a set of `INTEGER` or `FLOAT` values.

``avg(expression)``

Returns:

 Either an `INTEGER` or a `FLOAT`, depending on the values returned by `expression` and whether or not the calculation overflows.

Arguments:

Name Description

`expression`

An expression returning a set of numeric values.

Considerations:

 Any `null` values are excluded from the calculation. `avg(null)` returns `null`.
Example 1. avg()
Query
``````MATCH (p:Person)
RETURN avg(p.age)``````

The average of all the values in the property `age` is returned:

Table 1. Result
avg(p.age)

`61.8`

Rows: 1

## avg() - Durations

The function `avg()` returns the average of a set of `DURATION` values.

``avg(expression)``

Returns:

 `DURATION`

Arguments:

Name Description

`expression`

An expression returning a set of `DURATION` values.

Considerations:

 Any `null` values are excluded from the calculation. `avg(null)` returns `null`.
Example 2. avg()
Query
``````UNWIND [duration('P2DT3H'), duration('PT1H45S')] AS dur
RETURN avg(dur)``````

The average of the two supplied `DURATION` values is returned:

Table 2. Result
avg(dur)

`P1DT2H22.5S`

Rows: 1

## collect()

The function `collect()` returns a single aggregated list containing the values returned by an expression.

``collect(expression)``

Returns:

 A list containing heterogeneous elements; the types of the elements are determined by the values returned by `expression`.

Arguments:

Name Description

`expression`

An expression returning a set of values.

Considerations:

 Any `null` values are ignored and will not be added to the list. `collect(null)` returns an empty list.
Example 3. collect()
Query
``````MATCH (p:Person)
RETURN collect(p.age)``````

All the values are collected and returned in a single list:

Table 3. Result
collect(p.age)

`[58, 70, 55, 55, 71]`

Rows: 1

## count()

The function `count()` returns the number of values or rows, and appears in two variants:

`count(*)`

returns the number of matching rows.

`count(expr)`

returns the number of non-`null` values returned by an expression.

``count(expression)``

Returns:

 `INTEGER`

Arguments:

Name Description

`expression`

An expression.

Considerations:

 `count(*)` includes rows returning `null`. `count(expr)` ignores `null` values. `count(null)` returns `0`.
 Neo4j maintains a transactional count store for holding count metadata, which can significantly increase the speed of queries using the `count()` function. For more information about the count store, refer to Neo4j Knowledge Base → Fast counts using the count store.

### Using `count(*)` to return the number of nodes

The function `count(*)` can be used to return the number of nodes; for example, the number of nodes connected to a node `n`.

Example 4. count()
Query
``````MATCH (p:Person {name: 'Keanu Reeves'})-->(x)
RETURN labels(p), p.age, count(*)``````

The labels and `age` property of the start node `Keanu Reeves` and the number of nodes related to it are returned:

Table 4. Result
labels(p) p.age count(*)

`["Person"]`

`58`

`4`

Rows: 1

### Using `count(*)` to group and count relationship types

The function `count(*)` can be used to group the type of matched relationships and return the number of types.

Example 5. count()
Query
``````MATCH (p:Person {name: 'Keanu Reeves'})-[r]->()
RETURN type(r), count(*)``````

The type of matched relationships are grouped and the group count of relationship types is returned:

Table 5. Result
type(r) count(*)

`"ACTED_IN"`

`1`

`"KNOWS"`

`3`

Rows: 2

### Counting non-`null` values

Instead of simply returning the number of rows with `count(*)`, the function `count(expression)` can be used to return the number of non-`null` values returned by the expression.

Example 6. count()
Query
``````MATCH (p:Person)
RETURN count(p.age)``````

The number of nodes with the label `Person` and a property `age` is returned: (To calculate the sum, use `sum(n.age)`)

Table 6. Result
count(p.age)

`5`

Rows: 1

### Counting with and without duplicates

This example tries to find all friends of friends of `Keanu Reeves` and count them.

`count(DISTINCT friendOfFriend)`

Will only count a `friendOfFriend` once, as `DISTINCT` removes the duplicates.

`count(friendOfFriend)`

Will consider the same `friendOfFriend` multiple times.

Example 7. count()
Query
``````MATCH (p:Person)-->(friend:Person)-->(friendOfFriend:Person)
WHERE p.name = 'Keanu Reeves'
RETURN friendOfFriend.name, count(DISTINCT friendOfFriend), count(friendOfFriend)``````

The nodes `Carrie Anne Moss` and `Liam Neeson` both have an outgoing `KNOWS` relationship to `Guy Pearce`. The `Guy Pearce` node will, therefore, get counted twice when not using `DISTINCT`.

Table 7. Result
friendOfFriend.name count(DISTINCT friendOfFriend) count(friendOfFriend)

`"Guy Pearce"`

`1`

`2`

## max()

The function `max()` returns the maximum value in a set of values.

``max(expression)``

Returns:

 A property type, or a list, depending on the values returned by `expression`.

Arguments:

Name Description

`expression`

An expression returning a set containing any combination of property types and lists thereof.

Considerations:

 Any `null` values are excluded from the calculation. In a mixed set, any numeric value is always considered to be higher than any string value, and any string value is always considered to be higher than any list. Lists are compared in dictionary order, i.e. list elements are compared pairwise in ascending order from the start of the list to the end. `max(null)` returns `null`.
Example 8. max()
Query
``````UNWIND [1, 'a', null, 0.2, 'b', '1', '99'] AS val
RETURN max(val)``````

The highest of all the values in the mixed set — in this case, the numeric value `1` — is returned:

 The value `'99'` (a string), is considered to be a lower value than `1` (an integer), because `'99'` is a string.
Table 8. Result
max(val)

`1`

Rows: 1

Example 9. max()
Query
``````UNWIND [[1, 'a', 89], [1, 2]] AS val
RETURN max(val)``````

The highest of all the lists in the set — in this case, the list `[1, 2]` — is returned, as the number `2` is considered to be a higher value than the string `'a'`, even though the list `[1, 'a', 89]` contains more elements.

Table 9. Result
max(val)

`[1,2]`

Rows: 1

Example 10. max()
Query
``````MATCH (p:Person)
RETURN max(p.age)``````

The highest of all the values in the property `age` is returned:

Table 10. Result
max(p.age)

`71`

Rows: 1

## min()

The function `min()` returns the minimum value in a set of values.

``min(expression)``

Returns:

 A property type, or a list, depending on the values returned by `expression`.

Arguments:

Name Description

`expression`

An expression returning a set containing any combination of property types and lists thereof.

Considerations:

 Any `null` values are excluded from the calculation. In a mixed set, any string value is always considered to be lower than any numeric value, and any list is always considered to be lower than any string. Lists are compared in dictionary order, i.e. list elements are compared pairwise in ascending order from the start of the list to the end. `min(null)` returns `null`.
Example 11. min()
Query
``````UNWIND [1, 'a', null, 0.2, 'b', '1', '99'] AS val
RETURN min(val)``````

The lowest of all the values in the mixed set — in this case, the string value `"1"` — is returned. Note that the (numeric) value `0.2`, which may appear at first glance to be the lowest value in the list, is considered to be a higher value than `"1"` as the latter is a string.

Table 11. Result
min(val)

`"1"`

Rows: 1

Example 12. min()
Query
``````UNWIND ['d', [1, 2], ['a', 'c', 23]] AS val
RETURN min(val)``````

The lowest of all the values in the set — in this case, the list `['a', 'c', 23]` — is returned, as (i) the two lists are considered to be lower values than the string `"d"`, and (ii) the string `"a"` is considered to be a lower value than the numerical value `1`.

Table 12. Result
min(val)

`["a","c",23]`

Rows: 1

Example 13. min()
Query
``````MATCH (p:Person)
RETURN min(p.age)``````

The lowest of all the values in the property `age` is returned:

Table 13. Result
min(p.age)

`55`

Rows: 1

## percentileCont()

The function `percentileCont()` returns the percentile of the given value over a group, with a percentile from `0.0` to `1.0`. It uses a linear interpolation method, calculating a weighted average between two values if the desired percentile lies between them. For nearest values using a rounding method, see `percentileDisc`.

``percentileCont(expression, percentile)``

Returns:

 `FLOAT`

Arguments:

Name Description

`expression`

A numeric expression.

`percentile`

A numeric value between `0.0` and `1.0`.

Considerations:

 Any `null` values are excluded from the calculation. `percentileCont(null, percentile)` returns `null`.
Example 14. percentileCont()
Query
``````MATCH (p:Person)
RETURN percentileCont(p.age, 0.4)``````

The 40th percentile of the values in the property `age` is returned, calculated with a weighted average:

Table 14. Result
percentileCont(p.age, 0.4)

`56.8`

Rows: 1

## percentileDisc()

The function `percentileDisc()` returns the percentile of the given value over a group, with a percentile from `0.0` to `1.0`. It uses a rounding method and calculates the nearest value to the percentile. For interpolated values, see `percentileCont`.

``percentileDisc(expression, percentile)``

Returns:

 Either an `INTEGER` or a `FLOAT`, depending on the values returned by `expression` and whether or not the calculation overflows.

Arguments:

Name Description

`expression`

A numeric expression.

`percentile`

A numeric value between `0.0` and `1.0`.

Considerations:

 Any `null` values are excluded from the calculation. `percentileDisc(null, percentile)` returns `null`.
Example 15. percentileDisc()
Query
``````MATCH (p:Person)
RETURN percentileDisc(p.age, 0.5)``````

The 50th percentile of the values in the property `age` is returned:

Table 15. Result
percentileDisc(p.age, 0.5)

`58`

Rows: 1

## stDev()

The function `stDev()` returns the standard deviation for the given value over a group. It uses a standard two-pass method, with `N - 1` as the denominator, and should be used when taking a sample of the population for an unbiased estimate. When the standard variation of the entire population is being calculated, `stdDevP` should be used.

``stDev(expression)``

Returns:

 `FLOAT`

Arguments:

Name Description

`expression`

A numeric expression.

Considerations:

 Any `null` values are excluded from the calculation. `stDev(null)` returns `0`.
Example 16. stDev()
Query
``````MATCH (p:Person)
WHERE p.name IN ['Keanu Reeves', 'Liam Neeson', 'Carrie Anne Moss']
RETURN stDev(p.age)``````

The standard deviation of the values in the property `age` is returned:

Table 16. Result
stDev(p.age)

`7.937253933193772`

Rows: 1

## stDevP()

The function `stDevP()` returns the standard deviation for the given value over a group. It uses a standard two-pass method, with `N` as the denominator, and should be used when calculating the standard deviation for an entire population. When the standard variation of only a sample of the population is being calculated, `stDev` should be used.

``stDevP(expression)``

Returns:

 `FLOAT`

Arguments:

Name Description

`expression`

A numeric expression.

Considerations:

 Any `null` values are excluded from the calculation. `stDevP(null)` returns `0`.
Example 17. stDevP()
Query
``````MATCH (p:Person)
WHERE p.name IN ['Keanu Reeves', 'Liam Neeson', 'Carrie Anne Moss']
RETURN stDevP(p.age)``````

The population standard deviation of the values in the property `age` is returned:

Table 17. Result
stDevP(p.age)

`6.48074069840786`

Rows: 1

## sum() - Numeric values

The function `sum()` returns the sum of a set of numeric values.

``sum(expression)``

Returns:

 Either an `INTEGER` or a `FLOAT`, depending on the values returned by `expression`.

Arguments:

Name Description

`expression`

An expression returning a set of numeric values.

Considerations:

 Any `null` values are excluded from the calculation. `sum(null)` returns `0`.
Example 18. sum()
Query
``````MATCH (p:Person)
RETURN sum(p.age)``````

The sum of all the values in the property `age` is returned:

Table 18. Result
sum(p.age)

`309`

Rows: 1

## sum() - Durations

The function `sum()` returns the sum of a set of durations.

``sum(expression)``

Returns:

 `DURATION`

Arguments:

Name Description

`expression`

An expression returning a set of Durations.

Considerations:

 Any `null` values are excluded from the calculation.
Example 19. sum()
Query
``````UNWIND [duration('P2DT3H'), duration('PT1H45S')] AS dur
RETURN sum(dur)``````

The sum of the two supplied Durations is returned:

Table 19. Result
sum(dur)

`P2DT4H45S`

Rows: 1

## Aggregating expressions and grouping keys

Aggregating expressions are expressions which contain one or more aggregating functions. A simple aggregating expression consists of a single aggregating function. For instance, `sum(x.a)` is an aggregating expression that only consists of the aggregating function `sum( )` with `x.a` as its argument. Aggregating expressions are also allowed to be more complex, where the result of one or more aggregating functions are input arguments to other expressions. For instance, `0.1 * (sum(x.a) / count(x.b))` is an aggregating expression that contains two aggregating functions, `sum( )` with `x.a` as its argument and `count( )` with `x.b` as its argument. Both are input arguments to the division expression.

Grouping keys are non-aggregating expressions that are used to group the values going into the aggregating functions. For example, given the following query containing two return expressions, `n` and `count(*)`:

``RETURN n, count(*)``

The first, `n` is not an aggregating function, so it will be the grouping key. The latter, `count(*)` is an aggregating function. The matching paths will be divided into different buckets, depending on the grouping key. The aggregating function will then be run on these buckets, calculating an aggregate value per bucket.

The input expression of an aggregating function can contain any expression, including expressions that are not grouping keys. However, not all expressions can be composed with aggregating functions. The example below will throw an error since `n.x`, which is not a grouping key, is combined with the aggregating function `count(*)`.

``RETURN n.x + count(*)``

To sort the result set using aggregating functions, the aggregation must be included in the `ORDER BY` sub-clause following the `RETURN` clause.

### Examples

Example 20. Simple aggregation without any grouping keys
Query
``````MATCH (p:Person)
RETURN max(p.age)``````
Table 20. Result
max(p.age)

`71`

Rows: 1

Example 21. Addition of an aggregation and a constant, without any grouping keys
Query
``````MATCH (p:Person)
RETURN max(p.age) + 1``````
Table 21. Result
max(p.age) + 1

`72`

Rows: 1

Example 22. Subtraction of a property access and an aggregation

Note that `p` is a grouping key:

Query
``````MATCH (p:Person{name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p, p.age - max(f.age)``````
Table 22. Result
p p.age - max(f.age)

`{{"name":"Keanu Reeves","age":58}}`

`-13`

Rows: 1

Example 23. Subtraction of a property access and an aggregation.

Note that `p.age` is a grouping key:

Query
``````MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p.age, p.age - max(f.age)``````
Table 23. Result
p.age p.age - max(f.age)

`58`

`-13`

Rows: 1

Grouping keys themselves can be complex expressions. For better query readability, Cypher only recognizes a sub-expression in aggregating expressions as a grouping key if the grouping key is either:

• A variable - e.g. the `p` in `RETURN p, p.age - max(f.age)`.

• A property access - e.g. the `p.age` in `RETURN p.age, p.age - max(f.age)`.

• A map access - e.g. the `p.age` in `WITH {name:'Keanu Reeves', age:58} AS p RETURN p.age, p.age - max(p.age)`.

If more complex grouping keys are needed as operands in aggregating expression, it is always possible to project them in advance using `WITH`.

Using the property `p.age` will throw an exception, since `p.age` is not a grouping key. Therefore, it cannot be used in the expressions which contain the aggregating function. The below two queries would consequently return the same error message:

Query
``````MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p.age - max(f.age)``````
Query
``````MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
RETURN p.age + p.age, p.age + p.age - max(f.age)``````
Error message
``Aggregation column contains implicit grouping expressions. For example, in 'RETURN n.a, n.a + n.b + count(*)' the aggregation expression 'n.a + n.b + count(*)' includes the implicit grouping key 'n.b'. It may be possible to rewrite the query by extracting these grouping/aggregation expressions into a preceding WITH clause. Illegal expression(s): n.age``

However, the latter query would work if rewritten to:

Query
``````MATCH (p:Person {name:'Keanu Reeves'})-[:KNOWS]-(f:Person)
WITH p.age + p.age AS groupingKey, f
RETURN groupingKey, groupingKey - max(f.age)``````
Table 24. Result
groupingKey groupingKey - max(f.age)

`116`

`45`

Rows: 1

### Rules for aggregating expressions

For aggregating expressions to be correctly computable for the buckets formed by the grouping key(s), they have to fulfill some requirements. Specifically, each sub-expression in an aggregating expression has to be either:

• an aggregating function, e.g. `sum(x.a)`.

• a constant, e.g. `0.1`.

• a parameter, e.g. `\$param`.

• a grouping key, e.g. the `a` in `RETURN a, count(*)`.

• a local variable, e.g. the `x` in `count(*) + size([ x IN range(1, 10) | x ])`.

• a sub-expression, all operands of which have to be allowed in an aggregating expression.