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:

graph match clause

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.

Find all nodes in a graph
MATCH (n)
RETURN n
Table 1. Result
n

(:Person {"name":"Charlie Sheen"})

(:Person {"name":"Martin Sheen"})

(:Person {"name":"Michael Douglas"})

(:Person {"name":"Oliver Stone"})

(:Person {"name":"Rob Reiner"})

(:Movie {"title":"Wall Street"})

(:Movie {"title":"The American President"})

Rows: 7

Find nodes with a specific label

Find all nodes with the Movie label
MATCH (movie:Movie)
RETURN movie.title
Table 2. Result
movie.title

"Wall Street"

"The American President"

Rows: 2

MATCH using node label expressions

Node pattern using the OR (|) label expression
MATCH (n:Movie|Person)
RETURN n.name AS name, n.title AS title
Table 3. Result
name title

"Charlie Sheen"

<null>

"Martin Sheen"

<null>

"Michael Douglas"

<null>

"Oliver Stone"

<null>

"Rob Reiner"

<null>

<null>

"Wall Street"

<null>

"The American President"

Rows: 7

Node pattern using negation (!) label expression
MATCH (n:!Movie)
RETURN labels(n) AS label, count(n) AS labelCount
The above query uses the labels() and count() functions.
Table 4. Result
label labelCount

["Person", "Actor"]

3

["Person", "Director"]

2

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.

Find connected nodes using an empty relationship pattern
MATCH (:Person {name: 'Oliver Stone'})--(n)
RETURN n AS connectedNodes
Table 5. Result
connectedNodes

(:Movie {title: "Wall Street"})

Rows: 1

Directed relationship patterns

The direction of a relationship in a pattern is indicated by arrows: --> or <--.

Find all nodes connected to Oliver Stone by an outgoing relationship.
MATCH (:Person {name: 'Oliver Stone'})-->(movie:Movie)
RETURN movie.title AS movieTitle
Table 6. Result
movieTitle

"Wall Street"

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.

Find the types of an aliased relationship
MATCH (:Person {name: 'Oliver Stone'})-[r]->()
RETURN type(r) AS relType
The above query uses the type() function.
Table 7. Result
relType

"DIRECTED"

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.

Relationship pattern without direction
MATCH (a)-[:ACTED_IN {role: 'Bud Fox'}]-(b)
RETURN a, b
Table 8. Result
a b

(:Movie {"title":"Wall Street"})

(:Person {"name":"Charlie Sheen"})

(:Person {"name":"Charlie Sheen"})

(:Movie {"title":"Wall Street"})

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.

Relationship pattern filtering on the ACTED_IN relationship type
MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN]-(actor:Person)
RETURN actor.name AS actor
Table 9. Result
actor

"Michael Douglas"

"Martin Sheen"

"Charlie Sheen"

Rows: 3

MATCH using relationship type expressions

It is possible to match a pattern containing one of several relationship types using the OR symbol, |.

Relationship pattern including either ACTED_IN or DIRECTED relationship types
MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN|DIRECTED]-(person:Person)
RETURN person.name AS person
Table 10. Result
person

"Oliver Stone"

"Michael Douglas"

"Martin Sheen"

"Charlie Sheen"

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.

Graph pattern including several relationship patterns
MATCH (:Person {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(director:Person)
RETURN movie.title AS movieTitle, director.name AS director
Table 11. Result
movieTitle director

"Wall Street"

"Oliver Stone"

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.

Simple WHERE predicate
MATCH (charlie:Person)-[:ACTED_IN]->(movie:Movie)
WHERE charlie.name = 'Charlie Sheen'
RETURN movie.title AS movieTitle
Table 12. Result
movieTitle

"Wall Street"

Rows: 1

More complex WHERE predicate
MATCH (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.
Table 13. Result
movieTitle

"The American President"

Rows: 1

For more information, see the WHERE page.

MATCH with parameters

The MATCH clause can be used with parameters.

Parameters
{
  "movieTitle": "Wall Street",
  "actorRole": "Fox"
}
Find nodes using paramters
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.
Table 14. Result
actor role

"Charlie Sheen"

"Bud Fox"

"Martin Sheen"

"Carl Fox"

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.

Find all paths matching a pattern
MATCH path = ()-[:ACTED_IN]->(movie:Movie)
RETURN path
Table 15. Result
path

(:Person {name: "Charlie Sheen"})-[:ACTED_IN {role: "Bud Fox"}]→(:Movie {title: "Wall Street"})

(:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]→(:Movie {title: "Wall Street"})

(:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "A.J. MacInerney"}]→(:Movie {title: "The American President"})

(:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]→(:Movie {title: "Wall Street"})

(:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "President Andrew Shepherd"}]→(:Movie {title: "The American President"})

Rows: 5

Find paths matching a pattern including a WHERE predicate
MATCH path = (:Person)-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(:Person)
WHERE movie.title = 'Wall Street'
RETURN path
Table 16. Result
path

(:Person {name: "Charlie Sheen"})-[:ACTED_IN {role: "Bud Fox"}]→(:Movie {title: "Wall Street"})←[:DIRECTED]-(:Person {name: "Oliver Stone"})

(:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]→(:Movie {title: "Wall Street"})←[:DIRECTED]-(:Person {name: "Oliver Stone"})

(:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]→(:Movie {title: "Wall Street"})←[:DIRECTED]-(:Person {name: "Oliver Stone"})

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.

Chaining consecutive MATCH clauses
MATCH (: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.
Table 17. Result
director movieTitle

"Oliver Stone"

"Wall Street"

"Rob Reiner"

"The American President"

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.

Using WITH and multiple MATCH clauses
MATCH (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.
Table 18. Result
actor movieCount movies

"Martin Sheen"

2

["Wall Street", "The American President"]

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).

Syntax for matching node labels dynamically
MATCH (n:$(<expr>))
MATCH (n:$any(<expr>))
MATCH (n:$all(<expr>))
MATCH (n:$all(<expr>)) is functionally equivalent to MATCH (n:$(<expr>)).
Syntax for matching relationship types dynamically
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.

Match labels dynamically
WITH ["Person", "Director"] AS labels
MATCH (directors:$(labels))
RETURN directors
Table 19. Result
directors

(:Person:Director {name: "Oliver Stone"})

(:Person:Director {name: "Rob Reiner"})

Rows: 2

Match nodes dynamically using any()
MATCH (n:$any(["Movie", "Actor"]))
RETURN n AS nodes
Table 20. Result
nodes

(:Person:Actor {name: "Charlie Sheen"})

(:Person:Actor {name: "Martin Sheen"})

(:Person:Actor {name: "Michael Douglas"})

(:Movie {title: "Wall Street"})

(:Movie {title: "The American President"})

Rows: 5

Parameter
{
  "label": "Movie"
}
Match nodes dynamically using a parameter
MATCH (movie:$($label))
RETURN movie.title AS movieTitle
Table 21. Result
movieTitle

"Wall Street"

"The American President"

Rows: 2

Match relationships dynamically using a variable
CALL db.relationshipTypes()
YIELD relationshipType
MATCH ()-[r:$(relationshipType)]->()
RETURN relationshipType, count(r) AS relationshipCount
Table 22. Result
relationshipType relationshipCount

"ACTED_IN"

5

"DIRECTED"

2

Rows: 2

Performance caveats

MATCH 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.

As a result, MATCH queries using dynamic values cannot leverage index scans or seeks and must instead use the AllNodesScan operator, which reads all nodes from the node store and is therefore more costly.