Querying the graph

MATCH

The MATCH keyword in Cypher is what searches for an existing node, relationship, label, property, or pattern in the database. If you are familiar with SQL, MATCH works pretty much like SELECT in SQL.

WHERE

Not a clause in its own right, but adds constraints to a pattern, or filters the intermediate results.

RETURN

The RETURN keyword in Cypher specifies what values or results you might want to return from a Cypher query. You can tell Cypher to return nodes, relationships, node and relationship properties, or patterns in your query results. RETURN is not required when doing write procedures, but is needed for reads.

Just like with SQL, you can rename return results by using the AS keyword and aliasing the property with a cleaner name.

MATCH (p:Person)
RETURN p.name AS name

Let’s start creating a very simple network :

CREATE (a:Person {name: 'Messi'})
CREATE (b:Person {name: 'Neymar'})
CREATE (c:Person {name: 'DeBruyne'})
CREATE (d:Person {name: 'Lukaku'})
CREATE (e:Person {name: 'Vertongen'})
CREATE (a)-[:KNOWS]->(b)-[:KNOWS]->(d)
CREATE (a)-[:KNOWS]->(c)
CREATE (c)-[:KNOWS]->(d)
CREATE (c)-[:KNOWS]->(e)

which results in :

../_images/with1.png

Four elements can be returned by the RETURN clause:

  • Nodes

    MATCH (n {name: 'Lukaku'})
    RETURN n
    
  • Relationships

    ⚒ Find the outgoing relationships from the player with the name “Messi”

    MATCH (n {name: 'Messi'})-[r:KNOWS]->(c)
    RETURN r
    
  • Properties

    ⚒ Return all the properties from all the nodes of type person

    MATCH (n:Person)
    RETURN n.name
    
  • All elements

    In that case use “*” in the return statement.

WITH

The WITH clause allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next.

⚒ A list of the names of people in reverse order, limited to 3, is returned in a list.

MATCH (n)
WITH n
ORDER BY n.name DESC
LIMIT 3
RETURN collect(n.name)

results in: [“Vertongen”, “Neymar”, “Messi”]

You can match paths, limit to a certain number, and then match again using those paths as a base, as well as any number of similar limited searches.

⚒ Starting at ‘Messi’, find all matching nodes, order by name descending and get the top result, then find all the nodes connected to that top result, and return their names.

MATCH (n {name:'Messi'})--(m)
WITH m
ORDER BY m.name DESC
LIMIT 1
MATCH (m)--(o)
RETURN o.name

⚒ Find the name of the player connected to ‘Vertongen’ with the at least more than one outgoing relationship.

MATCH (player {name: 'Vertongen'})--(otherPerson)-->()
WITH otherPerson, count(*) AS foaf
WHERE foaf >0
RETURN otherPerson.name

This will return [“DeBruyne”]

UNWIND

With UNWIND, you can transform any list back into individual rows. These lists can be parameters that were passed in, previously collected result or other list expressions.

WITH
[1, 2] AS a,
[3, 4] AS b
UNWIND (a + b) AS x
RETURN x

The two lists — a and b — are concatenated to form a new list, which is then operated upon by UNWIND.

LIMIT

To return a limited subset of the rows, use this syntax:

MATCH (n)
RETURN n.name
ORDER BY n.name
LIMIT 3

REMOVE

Neo4j doesn’t allow storing null in properties. Instead, if no value exists, the property is just not there. So, REMOVE is used to remove a property value from a node or a relationship.

MATCH (a {name: 'Andy'})
REMOVE a.age
RETURN a.name, a.age

It is also possible to remove a label from a node using the REMOVE clause. The code below removes all the GoalKeeper labels.

MATCH (n)
REMOVE n:GoalKeeper
RETURN n.name, labels(n)

FOREACH

To study the concept better, let’s add some new nodes to the graph:

create (a:Person {name:'A'})
create (b:Person {name:'B'})
create (c:Person {name:'C'})
create (d:Person {name:'D'})
create (a)-[:GIVES_MONEY]->(b)
create (b)-[:GIVES_MONEY]->(c)
create (c)-[:GIVES_MONEY]->(d)
match (a)-[:GIVES_MONEY]->(b)
return a,b

This results in :

../_images/foreach.png

We can run through the path from person A to person B, and change the property of the different nodes along the way.

MATCH p=(start)-[*]->(finish)
WHERE start.name = 'A' AND finish.name = 'D'
FOREACH (n IN nodes(p) | SET n.suspicious = false)

Within the FOREACH parentheses, you can do any of the updating commands: SET, REMOVE, CREATE, MERGE, DELETE, and FOREACH.

Last change: Oct 30, 2023