11.2. Optional Match

The OPTIONAL MATCH clause is used to search for the pattern described in it, while using NULLs for missing parts of the pattern.

Introduction

OPTIONAL MATCH matches patterns against your graph database, just like MATCH does. The difference is that if no matches are found, OPTIONAL MATCH will use NULLs for missing parts of the pattern. OPTIONAL MATCH could be considered the Cypher equivalent of the outer join in SQL.

Either the whole pattern is matched, or nothing is matched. Remember that WHERE is part of the pattern description, and the predicates will be considered while looking for matches, not after. This matters especially in the case of multiple (OPTIONAL) MATCH clauses, where it is crucial to put WHERE together with the MATCH it belongs to.

[Tip]Tip

To understand the patterns used in the OPTIONAL MATCH clause, read Section 9.6, “Patterns”.

The following graph is used for the examples below:

Figure 11.4. Graph

Relationship

If a relationship is optional, use the OPTIONAL MATCH clause. This is similar to how a SQL outer join works. If the relationship is there, it is returned. If it’s not, NULL is returned in it’s place.

Query 

MATCH (a:Movie { title: 'Wall Street' })
OPTIONAL MATCH (a)-->(x)
RETURN x

Returns NULL, since the node has no outgoing relationships.

Result

x
1 row

<null>

Try this query live create (_0:`Movie` {`name`:"WallStreet", `title`:"Wall Street"}) create (_1:`Person` {`name`:"Rob Reiner"}) create (_2:`Movie` {`name`:"TheAmericanPresident", `title`:"The American President"}) create (_3:`Person` {`name`:"Oliver Stone"}) create (_4:`Person` {`name`:"Charlie Sheen"}) create (_5:`Person` {`name`:"Michael Douglas"}) create (_6:`Person` {`name`:"Martin Sheen"}) create (_1)-[:`DIRECTED`]->(_2) create (_3)-[:`DIRECTED`]->(_0) create (_4)-[:`FATHER`]->(_6) create (_4)-[:`ACTED_IN`]->(_0) create (_5)-[:`ACTED_IN`]->(_2) create (_5)-[:`ACTED_IN`]->(_0) create (_6)-[:`ACTED_IN`]->(_2) create (_6)-[:`ACTED_IN`]->(_0) ; match (a:Movie {title: 'Wall Street'}) optional match (a)-->(x) return x

Properties on optional elements

Returning a property from an optional element that is NULL will also return NULL.

Query 

MATCH (a:Movie { title: 'Wall Street' })
OPTIONAL MATCH (a)-->(x)
RETURN x, x.name

Returns the element x (NULL in this query), and NULL as its name.

Result

xx.name
1 row

<null>

<null>

Try this query live create (_0:`Movie` {`name`:"WallStreet", `title`:"Wall Street"}) create (_1:`Person` {`name`:"Rob Reiner"}) create (_2:`Movie` {`name`:"TheAmericanPresident", `title`:"The American President"}) create (_3:`Person` {`name`:"Oliver Stone"}) create (_4:`Person` {`name`:"Charlie Sheen"}) create (_5:`Person` {`name`:"Michael Douglas"}) create (_6:`Person` {`name`:"Martin Sheen"}) create (_1)-[:`DIRECTED`]->(_2) create (_3)-[:`DIRECTED`]->(_0) create (_4)-[:`FATHER`]->(_6) create (_4)-[:`ACTED_IN`]->(_0) create (_5)-[:`ACTED_IN`]->(_2) create (_5)-[:`ACTED_IN`]->(_0) create (_6)-[:`ACTED_IN`]->(_2) create (_6)-[:`ACTED_IN`]->(_0) ; match (a:Movie {title: 'Wall Street'}) optional match (a)-->(x) return x, x.name

Optional typed and named relationship

Just as with a normal relationship, you can decide which variable it goes into, and what relationship type you need.

Query 

MATCH (a:Movie { title: 'Wall Street' })
OPTIONAL MATCH (a)-[r:ACTS_IN]->()
RETURN r

This returns a node, and NULL, since the node has no outgoing ACTS_IN relationships.

Result

r
1 row

<null>

Try this query live create (_0:`Movie` {`name`:"WallStreet", `title`:"Wall Street"}) create (_1:`Person` {`name`:"Rob Reiner"}) create (_2:`Movie` {`name`:"TheAmericanPresident", `title`:"The American President"}) create (_3:`Person` {`name`:"Oliver Stone"}) create (_4:`Person` {`name`:"Charlie Sheen"}) create (_5:`Person` {`name`:"Michael Douglas"}) create (_6:`Person` {`name`:"Martin Sheen"}) create (_1)-[:`DIRECTED`]->(_2) create (_3)-[:`DIRECTED`]->(_0) create (_4)-[:`FATHER`]->(_6) create (_4)-[:`ACTED_IN`]->(_0) create (_5)-[:`ACTED_IN`]->(_2) create (_5)-[:`ACTED_IN`]->(_0) create (_6)-[:`ACTED_IN`]->(_2) create (_6)-[:`ACTED_IN`]->(_0) ; match (a:Movie {title: 'Wall Street'}) optional match (a)-[r:ACTS_IN]->() return r