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 variable a
.
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 variable 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
Caution Variable length pattern matching in versions 2.1.x and earlier does not enforce relationship uniqueness for patterns described inside of a single |
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 |
|
|
Try this query live create (_0 {`name`:"Anders"}) create (_1 {`name`:"Becky"}) create (_2 {`name`:"Cesar"}) create (_3 {`name`:"Dilshad"}) create (_4 {`name`:"Emil"}) create (_5 {`name`:"Filipa"}) create (_0)-[:`KNOWS`]->(_3) create (_0)-[:`KNOWS`]->(_2) create (_0)-[:`KNOWS`]->(_1) create (_1)-[:`KNOWS`]->(_4) create (_2)-[:`KNOWS`]->(_4) create (_3)-[:`KNOWS`]->(_5) ; 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 variables
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.