Neo4j can be applied in numerous situations: when your data is highly connected, queries are starting to become long complex to read & understand
=> Neo4j can help simplify your data model
Basic queies
- help:topic to open help
- OPTIONAL // still show column name as null if not exist
MATCH (movie:Movie)
OPTIONAL MATCH (director:Person)-[:ACTED_IN]->(movie)<-[:DIRECTED]-(director)
RETURN movie.title, director.name
- Multiple relationship
MATCH (person:Person)-[:ACTED_IN | WROTE | FUNDED]->(movie:Movie)
WHERE movie.title = 'Unforgiven' AND NOT (person)-[:DIRECTED]->(movie)
RETURN person, movie
- Regex
MATCH (movie:Movie)
WHERE movie.title =~ '(?i).+The.*'
return movie
- ORDER BY, SKIP, AS
MATCH (actor:Person)-[role:ACTED_IN]->(movie:Movie)
WHERE movie.title = 'Top Gun'
RETURN actor.name AS Name, role.earnings AS Earnt
ORDER BY role.earnings DESC
SKIP 3
- Logo, Blog, Bookmark, Search, Nav by tech, Darkmode
- DISTINCT, COUNT, AVG, SUM, MIN, MAX
- toString, replace("hello", "l", "r"), trim, upper, ceil, round
MATCH (tom:Person{name: 'Tom Hanks'})
MATCH (tom)-[:HAS_CONTACT]->(person:Person)
MATCH (person)-[role:ACTED_IN]->(movie:Movie)
WHERE person.born >= 1960 and role.earnings > 10000000
RETURN person.name AS ContactName, person.born, role.earnings as Earnt
ORDER BY role.earnings DESC
- CREATE
CREATE(cat:Cat:Animal{sound: 'Meow'})-[:GROOMS{period: 'Daily'}]->(cat),
(joe:Bunny:Animal{name: 'Joe')
- Add relationship to existing node. UNIQUE to prevent duplicating relationship
MATCH (joe:Bunny:Animal{name: 'Joe'}),
(cat:Cat:Animal{sound: 'Meow'})
CREATE UNIQUE (joe)-[:LIKE]->(cat),
(joe)-[:LIKE]->(andrew:Fox:Animal{name: 'Andrew'})
return joe, cat, andrew
Delete
- This delete every node with any relationship. So if there's any node with no relationships, it will remains
MATCH (n)-[rel]-() DELETE n, rel
- This delete every node even without any relationship
MATCH (n) DELETE n
- We can combine above code like this
MATCH (node)
OPTIONAL MATCH (node)-[rel]-()
DELETE node, rel
- Or use DETACH to delete node and its relationship
MATCH (n) DETACH DELETE n
Update
SET, REMOVE properties, labels
MATCH (tom:Person{name: 'Tom Hanks'})
SET tom:Handsome
REMOVE tom.sex,
tom:Handsome // remove label Handsome
RETURN tom
SET generated value
<i>WITH</i> breaks up a query into two different parts. We use value we need from the top to generate value for the bottom
MATCH (tom:Person{name: 'Tom Hanks'})-[:HAS_CONTACT]->(contact)
WITH tom, count(contact) AS num_of_contacts
SET tom.num_of_contacts = num_of_contacts
RETURN tom
Changing relationship types
There's no built in way that allows us to simply change a relationship type.
MATCH (tom:Person{name: 'Tom Hanks'})-[orig_rel:HAS_CONTACT]->(halle:Person{name: 'Halle Berry'})
CREATE (tom)-[new_rel:NEW_CONTACT]->(halle)
SET new_rel = orig_rel // copy all properties
DELETE orig_rel
RETURN tom, halle
Working with NULL
- NULL <> | = NULL return nothing; NULL IN [1,2,NULL] return null, so don't use operators with NULL
- Array can insert like this
WITH(['Add 1', 'Add 2'] + person.name) as destinations
- If new element may be NULL, put it in a array
WITH(['Add 1', 'Add 2'] + [person.name]) as destinations
- User <i>|</i> to pipe
RETURN [address in destinations WHERE address IS NOT NULL | address]
MATCH (person:Person) WHERE person.address IS NOT NULL RETURN person
MERGE
- Use MERGE to create if not exist
MERGE (lily:Person{name: 'Lily James'}) return lily
- Use ON CREATE SET or ON MATCH SET to combine with MERGE
MERGE (location:Lacation{name: 'San Francisco'})
ON CREATE SET location.created_at = timestamp(),
location.created_by = 'MA',
location.update_count = 0
ON MATCH SET location.updated_at = timestamp(),
location.update_count = location.update_count + 1
RETURN location
Working with paths
- If specify *0 means we're gonna get the first node back
MATCH (keanu:Person{name: 'Keanu Reeves'})-[rel:HAS_CONTACT*]->(contact) // there're between 1 and infinity HAS_CONTACT between Keanu and another node
RETURN keanu, rel, contact
LIMIT 3
- Get path length
MATCH (keanu:Person{name: 'Keanu Reeves'})
MATCH (tom:Person{name: 'Tom Hanks})
MATCH path = shortestPath((keanu)-[:HAS_CONTACT*..20]->(tom))
RETURN path, length(path) AS path_length
```cypher
MATCH (maxtrixActor:Person)-[:ACTED_IN]->(matrix:Moive{title: 'The Matrix'}),
(topGunActor:Person)-[:ACTED_IN]->(topGun:Movie{title: 'Top Gun}),
path = shortestPath((matrixActor)-[:HAS_CONTACT*..20]->(topGunActor))
WHERE matrixActor <> topGunActor
RETURN matrix, topGun, path, length(path) AS pathLength
ORDER BY pathLength // shotest of the shotest paths
LIMIT 3