8.8. Patterns

Patterns and pattern-matching are at the very heart of Cypher, so being effective with Cypher requires a good understanding of patterns.

Using patterns, you describe the shape of the data you’re looking for. For example, in the MATCH clause you describe the shape with a pattern, and Cypher will figure out how to get that data for you.

The pattern describes the data using a form that is very similar to how one typically draws the shape of property graph data on a whiteboard: usually as circles (representing nodes) and arrows between them to represent relationships.

Patterns appear in multiple places in Cypher: in MATCH, CREATE and MERGE clauses, and in pattern expressions. Each of these is described in more details in:

Patterns for nodes

The very simplest “shape” that can be described in a pattern is a node. A node is described using a pair of parentheses, and is typically given a name. For example:

(a)

This simple pattern describes a single node, and names that node using the identifier a.

Note that the parentheses may be omitted, but only when there are no labels or properties specified for the node pattern.

Labels

In addition to simply describing the shape of a node in the pattern, one can also describe attributes. The most simple attribute that can be described in the pattern is a label that the node must have. For example:

(a:User)-->(b)

One can also describe a node that has multiple labels:

(a:User:Admin)-->(b)

Specifying properties

Nodes and relationships are the fundamental structures in a graph. Neo4j uses properties on both of these to allow for far richer models.

Properties can be expressed in patterns using a map-construct: curly brackets surrounding a number of key-expression pairs, separated by commas. E.g. a node with two properties on it would look like: (a { name: "Andres", sport: "Brazilian Ju-Jitsu" }).

A relationship with expectations on it would could look like: (a)-[{blocked: false}]->(b).

When properties appear in patterns, they add an additional constraint to the shape of the data. In the case of a CREATE clause, the properties will be set in the newly created nodes and relationships. In the case of a MERGE clause, the properties will be used as additional constraints on the shape any existing data must have (the specified properties must exactly match any existing data in the graph). If no matching data is found, then MERGE behaves like CREATE and the properties will be set in the newly created nodes and relationships.

Note that patterns supplied to CREATE may use a single parameter to specify properties, e.g: CREATE (node {paramName}). This is not possible with patterns used in other clauses, as Cypher needs to know the property names at the time the query is compiled, so that matching can be done effectively.

Describing relationships

The simplest way to describe a relationship is by using the arrow between two nodes, as in the previous examples. Using this technique, you can describe that the relationship should exist and the directionality of it. If you don’t care about the direction of the relationship, the arrow head can be omitted, like so:

(a)--(b)

As with nodes, relationships may also be given names. In this case, a pair of square brackets is used to break up the arrow and the identifier is placed between. For example:

(a)-[r]->(b)

Much like labels on nodes, relationships can have types. To describe a relationship with a specific type, you can specify this like so:

(a)-[r:REL_TYPE]->(b)

Unlike labels, relationships can only have one type. But if we’d like to describe some data such that the relationship could have any one of a set of types, then they can all be listed in the pattern, separating them with the pipe symbol | like this:

(a)-[r:TYPE1|TYPE2]->(b)

Note that this form of pattern can only be used to describe existing data (ie. when using a pattern with MATCH or as an expression). It will not work with CREATE or MERGE, since it’s not possible to create a relationship with multiple types.

As with nodes, the name of the relationship can always be omitted, in this case like so:

(a)-[:REL_TYPE]->(b)

Variable length

Rather than describing a long path using a sequence of many node and relationship descriptions in a pattern, many relationships (and the intermediate nodes) can be described by specifying a length in the relationship description of a pattern. For example:

(a)-[*2]->(b)

This describes a graph of three nodes and two relationship, all in one path (a path of length 2). This is equivalent to:

(a)-->()-->(b)

A range of lengths can also be specified: such relationship patterns are called “variable length relationships”. For example:

(a)-[*3..5]->(b)

This is a minimum length of 3, and a maximum of 5. It describes a graph of either 4 nodes and 3 relationships, 5 nodes and 4 relationships or 6 nodes and 5 relationships, all connected together in a single path.

Either bound can be omitted. For example, to describe paths of length 3 or more, use:

(a)-[*3..]->(b)

And to describe paths of length 5 or less, use:

(a)-[*..5]->(b)

Both bounds can be omitted, allowing paths of any length to be described:

(a)-[*]->(b)

As a simple example, let’s take the query below:

Query. 

MATCH (me)-[:KNOWS*1..2]-(remote_friend)
WHERE me.name = "Filipa"
RETURN remote_friend.name

Result

remote_friend.name
2 rows

"Dilshad"

"Anders"

Try this query live. create (_0 {`name`:"Dilshad"}) create (_1 {`name`:"Emil"}) create (_2 {`name`:"Filipa"}) create (_3 {`name`:"Anders"}) create (_4 {`name`:"Becky"}) create (_5 {`name`:"Cesar"}) create _0-[:`KNOWS`]->_2 create _3-[:`KNOWS`]->_0 create _3-[:`KNOWS`]->_5 create _3-[:`KNOWS`]->_4 create _4-[:`KNOWS`]->_1 create _5-[:`KNOWS`]->_1 MATCH (me)-[:KNOWS*1..2]-(remote_friend) WHERE me.name = "Filipa" RETURN remote_friend.name

This query finds data in the graph which a shape that fits the pattern: specifically a node (with the name property Filipa) and then the KNOWS related nodes, one or two steps out. This is a typical example of finding first and second degree friends.

Note that variable length relationships can not be used with CREATE and MERGE.

Assigning to path identifiers

As described above, a series of connected nodes and relationships is called a "path". Cypher allows paths to be named using an identifer, like so:

p = (a)-[*3..5]->(b)

You can do this in MATCH, CREATE and MERGE, but not when using patterns as expressions.