MATCH
The MATCH
clause enables you to define specific patterns that the database will search for within its graph structure.
The MATCH
clause can specify the nodes, relationships, and properties in a pattern, allowing for queries that traverse the graph to retrieve relevant data.
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 (charlie:Person:Actor {name: 'Charlie Sheen'}),
(martin:Person:Actor {name: 'Martin Sheen'}),
(michael:Person:Actor {name: 'Michael Douglas'}),
(oliver:Person:Director {name: 'Oliver Stone'}),
(rob:Person:Director {name: 'Rob Reiner'}),
(wallStreet:Movie {title: 'Wall Street'}),
(charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet),
(martin)-[:ACTED_IN {role: 'Carl Fox'}]->(wallStreet),
(michael)-[:ACTED_IN {role: 'Gordon Gekko'}]->(wallStreet),
(oliver)-[:DIRECTED]->(wallStreet),
(thePresident:Movie {title: 'The American President'}),
(martin)-[:ACTED_IN {role: 'A.J. MacInerney'}]->(thePresident),
(michael)-[:ACTED_IN {role: 'President Andrew Shepherd'}]->(thePresident),
(rob)-[:DIRECTED]->(thePresident)
Find nodes
The MATCH
clause allows you to specify node patterns of varying complexity to retrieve from a graph.
For more information about finding node patterns, see Patterns → Node patterns.
Find all nodes
By specifying a pattern with a single node and no labels, all nodes in the graph will be returned.
MATCH (n)
RETURN n
n |
---|
|
|
|
|
|
|
|
Rows: 7 |
Find nodes with a specific label
Movie
labelMATCH (movie:Movie)
RETURN movie.title
movie.title |
---|
|
|
Rows: 2 |
MATCH using node label expressions
OR
(|
) label expressionMATCH (n:Movie|Person)
RETURN n.name AS name, n.title AS title
name | title |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rows: 7 |
!
) label expressionMATCH (n:!Movie)
RETURN labels(n) AS label, count(n) AS labelCount
label | labelCount |
---|---|
|
|
|
|
Rows: 2 |
For a list of all label expressions supported by Cypher®, see Patterns → Label expressions.
Find relationships
The MATCH
clause allows you to specify relationship patterns of varying complexity to retrieve from a graph.
Unlike a node pattern, a relationship pattern cannot be used in a MATCH
clause without node patterns at both ends.
For more information about relationship patterns, see Patterns → Relationship patterns.
Relationships will only be matched once inside a single pattern. Read more about this behavior in the section on relationship uniqueness. |
Empty relationship patterns
By applying --
, a pattern will be matched for a relationship with any direction and without any filtering on relationship types or properties.
MATCH (:Person {name: 'Oliver Stone'})--(n)
RETURN n AS connectedNodes
connectedNodes |
---|
|
Rows: 1 |
Directed relationship patterns
The direction of a relationship in a pattern is indicated by arrows: -->
or <--
.
Oliver Stone
by an outgoing relationship.MATCH (:Person {name: 'Oliver Stone'})-->(movie:Movie)
RETURN movie.title AS movieTitle
movieTitle |
---|
|
Rows: 1 |
Relationship variables
It is possible to introduce a variable to a pattern, either for filtering on relationship properties or to return a relationship.
MATCH (:Person {name: 'Oliver Stone'})-[r]->()
RETURN type(r) AS relType
The above query uses the type() function.
|
relType |
---|
|
Rows: 1 |
MATCH on an undirected relationship
When a pattern contains a bound relationship, and that relationship pattern does not specify direction, Cypher will match the relationship in both directions.
MATCH (a)-[:ACTED_IN {role: 'Bud Fox'}]-(b)
RETURN a, b
a | b |
---|---|
|
|
|
|
Rows: 2 |
Filter on relationship types
It is possible to specify the type of a relationship in a relationship pattern by using a colon (:
) before the relationship type.
ACTED_IN
relationship typeMATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN]-(actor:Person)
RETURN actor.name AS actor
actor |
---|
|
|
|
Rows: 3 |
MATCH using relationship type expressions
It is possible to match a pattern containing one of several relationship types using the OR
symbol, |
.
ACTED_IN
or DIRECTED
relationship typesMATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN|DIRECTED]-(person:Person)
RETURN person.name AS person
person |
---|
|
|
|
|
Rows: 4 |
As relationships can only have exactly one type each, ()-[:A&B]→()
will never match a relationship.
For a list of all relationship type expressions supported by Cypher, see Patterns → Label expressions.
Find multiple relationships
A graph pattern can contain several relationship patterns.
MATCH (:Person {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(director:Person)
RETURN movie.title AS movieTitle, director.name AS director
movieTitle | director |
---|---|
|
|
Rows: 1 |
MATCH with WHERE predicates
The MATCH
clause is often paired with a WHERE
sub-clause, which adds predicates to refine the patterns, making them more specific.
These predicates are part of the pattern itself, not just filters applied after matching.
Thus, always place the WHERE
clause with its corresponding MATCH
clause.
WHERE
predicateMATCH (charlie:Person)-[:ACTED_IN]->(movie:Movie)
WHERE charlie.name = 'Charlie Sheen'
RETURN movie.title AS movieTitle
movieTitle |
---|
|
Rows: 1 |
WHERE
predicateMATCH (martin:Person)-[:ACTED_IN]->(movie:Movie)
WHERE martin.name = 'Martin Sheen' AND NOT EXISTS {
MATCH (movie)<-[:DIRECTED]-(director:Person {name: 'Oliver Stone'})
}
RETURN movie.title AS movieTitle
The above query uses an EXISTS subquery.
|
movieTitle |
---|
|
Rows: 1 |
For more information, see the WHERE
page.
MATCH with parameters
The MATCH
clause can be used with parameters.
{
"movieTitle": "Wall Street",
"actorRole": "Fox"
}
MATCH (:Movie {title: $movieTitle})<-[r:ACTED_IN]-(p:Person)
WHERE r.role CONTAINS $actorRole
RETURN p.name AS actor, r.role AS role
The above query uses the CONTAINS operator.
|
actor | role |
---|---|
|
|
|
|
Rows: 2 |
For more information about how to set parameters, see Syntax → Parameters.
Find paths
The MATCH
clause can also be used to bind whole paths to variables.
MATCH path = ()-[:ACTED_IN]->(movie:Movie)
RETURN path
path |
---|
|
|
|
|
|
Rows: 5 |
WHERE
predicateMATCH path = (:Person)-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(:Person)
WHERE movie.title = 'Wall Street'
RETURN path
path |
---|
|
|
|
Rows: 3 |
For more information about how MATCH
is used to find patterns of varying complexity (including quantified path patterns, quantified relationships, and the shortest paths between nodes), see the section on Patterns.
Multiple MATCH clauses, the WITH clause, and clause composition
In Cypher, the behavior of a query is defined by its clauses. Each clause takes the current graph state and a table of intermediate results, processes them, and passes the updated graph state and results to the next clause. The first clause starts with the graph’s initial state and an empty table, while the final clause produces the query result.
MATCH
clausesMATCH (:Person {name: 'Martin Sheen'})-[:ACTED_IN]->(movie:Movie) (1)
MATCH (director:Person)-[:DIRECTED]->(movie) (2)
RETURN director.name AS director, movie.title AS movieTitle
1 | The result of the first MATCH clause is the variable movie which holds all the Movies that Martin Sheen has ACTED_IN . |
2 | The second MATCH clause uses the movie variable to find any Person node with a DIRECTED relationship to those Movie nodes that Martin Sheen has ACTED_IN . |
director | movieTitle |
---|---|
|
|
|
|
Rows: 2 |
A variable can be implicitly carried over to the following clause by being referenced in another operation.
A variable can also be explicitly passed to the following clause using the WITH
clause.
If a variable is neither implicitly nor explicitly carried over to its following clause, it will be discarded and is not available for reference later in the query.
WITH
and multiple MATCH
clausesMATCH (actors:Person)-[:ACTED_IN]->(movies:Movie) (1)
WITH actors, count(movies) AS movieCount (2)
ORDER BY movieCount DESC
LIMIT 1 (3)
MATCH (actors)-[:ACTED_IN]->(movies) (4)
RETURN actors.name AS actor, movieCount, collect(movies.title) AS movies
1 | The Person and Movie nodes matched in this step are stored in variables, which are then passed on to the second row of the query. |
2 | The movies variable is implicitly imported by its occurrence in the count() function.
The WITH clause explicitly imports the actors variable. |
3 | An ORDER BY clause orders the results by movieCount in descending order, ensuring that the Person with the highest number of movies appears at the top, and LIMIT 1 ensures that all other Person nodes are discarded. |
4 | The second MATCH clause finds all Movie nodes associated with the Person nodes currently bound to the actors variable. |
The above query uses the collect() function.
|
actor | movieCount | movies |
---|---|---|
|
|
|
Rows: 1 |
For more information about how Cypher queries work, see Clause composition.
MATCH using dynamic node labels and relationship types
Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when matching nodes and relationships. This allows for more flexible queries and mitigates the risk of Cypher injection. (For more information about Cypher injection, see Neo4j Knowledge Base → Protecting against Cypher injection).
MATCH (n:$(<expr>))
MATCH (n:$any(<expr>))
MATCH (n:$all(<expr>))
MATCH (n:$all(<expr>)) is functionally equivalent to MATCH (n:$(<expr>)) .
|
MATCH ()-[r:$(<expr>))]->()
MATCH ()-[r:$any(<expr>)]->()
MATCH ()-[r:$all(<expr>))]->()
The expression must evaluate to a STRING NOT NULL | LIST<STRING NOT NULL> NOT NULL
value.
If you use a LIST<STRING>
with more than one item in a relationship pattern with dynamic relationship types, no results will be returned.
This is because a relationship can only have exactly one type.
Queries using dynamic values may not be as performant as those using static values. This is because the Cypher planner uses statically available information when planning queries to determine whether to use an index or not, and this is not possible when using dynamic values. |
WITH ["Person", "Director"] AS labels
MATCH (directors:$(labels))
RETURN directors
directors |
---|
|
|
Rows: 2 |
any()
MATCH (n:$any(["Movie", "Actor"]))
RETURN n AS nodes
nodes |
---|
|
|
|
|
|
Rows: 5 |
{
"label": "Movie"
}
MATCH (movie:$($label))
RETURN movie.title AS movieTitle
movieTitle |
---|
|
|
Rows: 2 |
CALL db.relationshipTypes()
YIELD relationshipType
MATCH ()-[r:$(relationshipType)]->()
RETURN relationshipType, count(r) AS relationshipCount
relationshipType | relationshipCount |
---|---|
|
|
|
|
Rows: 2 |