Neo4j Fundamentals
Cypher
Cypher is a query language designed for graphs.
Basics
- Nodes are represented by parentheses ()
- We use a colon to signify the label(s)
(:Person)
- Relationships between nodes are written with two dashes
(:Person)--(:Movie)
- The direction of a relationship is indicated using a greater than or less than symbol < or >
(:Person)-→(:Movie)
- The type of the relationship is written using the square brackets between the two dashes: [ and ]
[:ACTED_IN]
- Properties in Neo4j are key/value pairs,
{name: 'Tom Hanks'}
Reading
Return all nodes with Person label
MATCH (p:Person)
RETURN p
Return one node
MATCH (p:Person {name: 'Tom Hanks'})
RETURN p
In our Cypher statement, we can access properties using a dot notation. For example, to return the name property value using its property key p.name.
MATCH (p:Person {name: 'Tom Hanks'})
RETURN p.born
// or using where
MATCH (p:Person)
WHERE p.name = 'Tom Hanks'
RETURN p.born
TIP
In Cypher, labels, property keys, and variables are case-sensitive. Cypher keywords are not case-sensitive.
Neo4j best practices include:
- Name labels using CamelCase.
- Name property keys and variables using camelCase.
- User UPPERCASE for Cypher keywords.
Filtering
- Filtering by node labels
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE m.title='The Matrix'
RETURN p.name
- Filtering using ranges
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE 2000 <= m.released <= 2003
RETURN p.name, m.title, m.released
- Filtering by existence of a property
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name='Jack Nicholson' AND m.tagline IS NOT NULL
RETURN m.title, m.tagline
- Filtering by partial strings. You can specify:
STARTS WITH, ENDS WITH, and CONTAINS
MATCH (p:Person)-[:ACTED_IN]->()
WHERE toLower(p.name) STARTS WITH 'michael'
RETURN p.name
- Filtering by patterns in the graph
Suppose you wanted to find all people who wrote a movie but did not direct that same movie. Here is how you would perform the query:
MATCH (p:Person)-[:WROTE]->(m:Movie)
WHERE NOT exists( (p)-[:DIRECTED]->(m) )
RETURN p.name, m.title
- Filtering using lists
MATCH (p:Person)
WHERE p.born IN [1965, 1970, 1975]
RETURN p.name, p.born
Creating Nodes
We use the MERGE keyword to create a pattern in the database.
Note that when you use MERGE to create a node, you must specify at least one property that will be the unique primary key for the node.
MERGE (p:Person {name: 'Michael Caine'})
Executing multiple Cypher clauses
MERGE (p:Person {name: 'Katie Holmes'})
MERGE (m:Movie {title: 'The Dark Knight'})
RETURN p, m
Using CREATE instead of MERGE to create nodes
Cypher has a CREATE clause you can use for creating nodes. The benefit of using CREATE is that it does not look up the primary key before adding the node. You can use CREATE if you are sure your data is clean and you want greater speed during import. We use MERGE in this training because it eliminates duplication of nodes.
Creating Relationship
Just like you can use MERGE to create nodes in the graph, you use MERGE to create relationships between two nodes. First you must have references to the two nodes you will be creating the relationship for. When you create a relationship between two nodes, it must have:
- Type
- Direction
MATCH (p:Person {name: 'Michael Caine'})
MATCH (m:Movie {title: 'The Dark Knight'})
MERGE (p)-[:ACTED_IN]->(m)
Creating nodes and relationships using multiple clauses
MERGE (p:Person {name: 'Chadwick Boseman'})
MERGE (m:Movie {title: 'Black Panther'})
MERGE (p)-[:ACTED_IN]-(m)
WARNING
Note that in this MERGE clause where we create the relationships, we did not specify the direction of the relationship. By default, if you do not specify the direction when you create the relationship, it will always be assumed left-to-right.
Using MERGE to create nodes and a relationship in single clause
MERGE (p:Person {name: 'Emily Blunt'})-[:ACTED_IN]->(m:Movie {title: 'A Quiet Place'})
RETURN p, m
Updating Properties
Adding properties for a node or relationship
- Inline as part of the MERGE clause
MERGE (p:Person {name: 'Michael Caine'})
MERGE (m:Movie {title: 'Batman Begins'})
MERGE (p)-[:ACTED_IN {roles: ['Alfred Penny']}]->(m)
RETURN p,m
- Using the SET keyword for a reference to a node or relationship
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'Michael Caine' AND m.title = 'The Dark Knight'
SET r.roles = ['Alfred Penny'], r.year = 2008
RETURN p, r, m
Removing properties
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'Michael Caine' AND m.title = 'The Dark Knight'
REMOVE r.roles
RETURN p, r, m
or
MATCH (p:Person)
WHERE p.name = 'Gene Hackman'
SET p.born = null
RETURN p
Merge Tips
Define values during merge
MERGE (p:Person {name: 'McKenna Grace'})
ON CREATE SET p.createdAt = datetime()
ON MATCH SET p.updatedAt = datetime()
SET p.born = 2006
RETURN p
You can use MERGE to create nodes or relationships:
MERGE (p:Person {name: 'Michael Caine'})
MERGE (m:Movie {title: 'The Cider House Rules'})
MERGE (p)-[:ACTED_IN]->(m)
Another way your can create these nodes and relationship is as follows:
MERGE (p:Person {name: 'Michael Caine'})-[:ACTED_IN]->(m:Movie {title: 'The Cider House Rules'})
RETURN p, m
Delete Data
Node
MATCH (p:Person)
WHERE p.name = 'Jane Doe'
DELETE p
Before deleting a node, check the relationships, otherwise you can get this error:
DANGER
Neo.ClientError.Schema.ConstraintValidationFailed Cannot delete node<175>, because it still has relationships. To delete this node, you must first delete its relationships.
Relationship
MATCH (p:Person {name: 'Jane Doe'})-[r:ACTED_IN]->(m:Movie {title: 'The Matrix'})
DELETE r
RETURN p, m
Node and Relationship
Deleting a node and its relationships in the same command
MATCH (p:Person {name: 'Jane Doe'})
DETACH DELETE p
Labels
To remove a label you use the REMOVE clause. Run this code:
MATCH (p:Person {name: 'Jane Doe'})
REMOVE p:Developer
RETURN p
Counting
MATCH (u:User)-[:RATED]-(m:Movie)
WHERE m.title = 'Apollo 13'
RETURN count(*) AS `Number of reviewers`