FILTER
FILTER
is used to add filters to queries, similar to Cypher®'s WHERE
.
Unlike WHERE
, FILTER
is not a subclause, which means it can be used independently of the MATCH
, OPTIONAL MATCH
, and WITH
clauses, but not within them.
Example graph
The following graph is used for the examples below:
To recreate the graph, run the following query in an empty Neo4j database:
CREATE (andy:Swedish:Person {name: 'Andy', age: 36}),
(timothy:Person {name: 'Timothy', age: 38}),
(peter:Person {name: 'Peter', age: 35}),
(lisa:Person {name: 'Lisa', age: 48}),
(john:Person {name: 'John', age: 40}),
(susan:Person {name: 'Susan', age: 32}),
(andy)-[:KNOWS {since: 2012}]->(timothy),
(andy)-[:KNOWS {since: 1999}]->(peter),
(peter)-[:KNOWS {since: 2005}]->(lisa),
(lisa)-[:KNOWS {since: 2010}]->(john),
(john)-[:KNOWS {since: 2021}]->(susan)
Basic filtering
MATCH (n)
FILTER n:Swedish
RETURN n.name AS name
name |
---|
|
|
MATCH (n:Person)
FILTER n.age < 35
RETURN n.name AS name, n.age AS age
name | age |
---|---|
|
|
|
MATCH (p:Person)-[r:KNOWS]->(n:Person)
FILTER r.since > 2010
RETURN p.name AS person,
r.since AS knowsSince,
n.name AS otherPerson
person | knowsSince | otherPerson |
---|---|---|
|
|
|
|
|
|
|
Filter on dynamic properties
To filter on a property using a dynamically computed name, use square brackets []
:
{
"propname": "age"
}
MATCH (n:Person)
FILTER n[$propname] > 40
RETURN n.name AS name, n.age AS age
name | age |
---|---|
|
|
Rows: 1 |
Differences between FILTER
and WHERE
FILTER
and WHERE
are both used to apply filter to queries.
However, there are a number of important differences between them that arise from the fact that FILTER
is a clause and WHERE
is a subclause:
-
While
WHERE
should not be understood as a filter after the matching is finished (it should rather be seen as adding constraints to a described pattern),FILTER
should be understood as performing post-match filtering, and not as adding constraints to a described patterns. -
FILTER
cannot be used withinMATCH
,OPTIONAL MATCH
, orWITH
clauses but only alongside them. This means that, unlikeWHERE
,FILTER
cannot be used to add filters inside patterns.
FILTER
and WHERE
This OPTIONAL MATCH
example highlights the differences between the WHERE
subclause and the FILTER
clause.
WHERE
constraining an OPTIONAL MATCH
patternUNWIND [32,37,40] AS ages
OPTIONAL MATCH (p:Person)
WHERE p.age = ages
RETURN p.name AS name, p.age AS age
name | age |
---|---|
|
|
|
|
|
|
Rows: 3 |
Because WHERE
is a subclause belonging to OPTIONAL MATCH
, it only filters the matches, but does not affect the number of returned rows.
In this case, OPTIONAL MATCH
always keeps all rows from UNWIND
, and WHERE
does not remove any rows returning NULL.
The same is not true if WHERE
is exchanged for FILTER
:
FILTER
adding post-filtering to OPTIONAL MATCH
UNWIND [32,37,40] AS ages
OPTIONAL MATCH (p:Person)
FILTER p.age = ages
RETURN p.name
name | age |
---|---|
|
|
|
|
Rows: 2 |
Unlike WHERE
, FILTER
is not part of the OPTIONAL MATCH
and so removes entire rows from the result set based on the condition provided within the expression.
That is, when OPTIONAL MATCH
fails to find a match and p
is NULL
, FILTER p.age = ages
cannot be evaluated, causing the entire row to be removed.
FILTER
cannot be used within patternsBecause WHERE
is a subclause qualifying a described pattern, it can be used inside patterns.
WHERE
inside a node patternWITH 35 AS minAge
MATCH (a:Person WHERE a.name = 'Andy')-[:KNOWS]->(b:Person WHERE b.age > minAge)
RETURN b.name AS name`
name |
---|
|
Rows: 1 |
The same is not true for FILTER
which, as a clause, cannot be placed with a pattern.
FILTER
inside a patternWITH 35 AS minAge
MATCH (a:Person FILTER a.name = 'Andy')-[:KNOWS]->(b:Person FILTER b.age > minAge)
RETURN b.name AS name
For more information about how to use WHERE
in fixed-length and variable-length pattern matching, see WHERE
→ Filter patterns.
FILTER
as a substitute for WITH * WHERE
Unlike WHERE
, which relies on MATCH
, OPTIONAL MATCH
, or WITH
to define its scope, FILTER
can filter queries independently of these clauses.
This can make some queries more concise.
For example, the following two queries are equivalent:
WITH * WHERE
UNWIND [1, 2, 3, 4, 5, 6] AS x
WITH x
WHERE x > 2
RETURN x
FILTER
UNWIND [1, 2, 3, 4, 5, 6] AS x
FILTER x > 2
RETURN x
As such, FILTER
can be seen as a substitute for the WITH * WHERE <predicate>
constructs in Cypher.
FILTER
instead of WITH * WHERE
in LOAD CSV
The following two LOAD CSV
commands are equivalent:
Id,Name,Location,Email,BusinessType
1,Neo4j,San Mateo,contact@neo4j.com,P
2,AAA,,info@aaa.com,
3,BBB,Chicago, info@ ,G
,CCC,Michigan,info@ccc.com,G
LOAD CSV
using WITH * WHERE
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
WITH row
WHERE row.Id IS NOT NULL
MERGE (c:Company {id: row.Id})
LOAD CSV
using FILTER
LOAD CSV WITH HEADERS FROM 'file:///companies.csv' AS row
FILTER row.Id IS NOT NULL
MERGE (c:Company {id: row.Id})
However, while FILTER
can act as a substitute for WITH * WHERE <predicate>
constructs, it does not include the ability of WITH
to manipulate the variables in scope for subsequent clauses.
Nor can FILTER
alias or create new variables.
In other words, FILTER
only has the function of WITH * WHERE <predicate>
and not WITH <selectedVariable> AS <newVariableName> WHERE <predicate>
.