Cypher Query Language – The Heart of Neo4j

1. What is Cypher?

  • Cypher is Neo4j’s query language — like SQL for relational databases.

  • It’s designed to read and write graph data in a way that looks visually like the graph itself.

  • Queries describe patterns of nodes and relationships using ASCII-art-like syntax.


2. Basic Syntax Building Blocks

a) Nodes

  • Written inside parentheses ().

  • Can have:

    • Label: (:User)

    • Properties: (:User {name: "Alice"})

(:User {name: "Alice", role: "Developer"})

b) Relationships

  • Written inside square brackets [] with arrows --> or <--.

  • Have:

    • Type: [:WORKS_ON]

    • Properties: [:WORKS_ON {since: 2023}]

(Alice)-[:WORKS_ON]->(ProjectX)

c) Variables

  • You can give names to nodes or relationships to use later in the query.

(u:User {name: "Alice"})-[:WORKS_ON]->(p:Project)

Here:

  • u = variable for the User node.

  • p = variable for the Project node.


d) MATCH — Reading Data

Find patterns in the graph.

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN u.name, p.name;
  • Finds all users and their projects.


e) CREATE — Adding Data

Add new nodes and relationships.

CREATE (:User {name: "Alice", role: "Developer"}) CREATE (:Project {name: "Apollo"})

Or in one go:

CREATE (:User {name: "Alice"})-[:WORKS_ON {since: 2023}]->(:Project {name: "Apollo"})

f) WHERE — Filtering

MATCH (u:User)-[:WORKS_ON]->(p:Project) WHERE u.role = "Developer" RETURN u.name, p.name;

g) RETURN — Output

Decides what to show.

RETURN u.name, p.name;

h) MERGE — Create if not exists

MERGE (u:User {name: "Alice"})
  • If Alice exists, returns her; if not, creates her.


i) DELETE — Removing

MATCH (u:User {name: "Alice"}) DELETE u;

3. Example from a Use Case

CREATE (u:User {name: "Alice", role: "Developer"}) CREATE (p:Project {name: "Apollo"}) CREATE (a:Application {name: "TimeTracker"}) CREATE (u)-[:WORKS_ON {since: 2023}]->(p) CREATE (p)-[:HAS_ACCESS_TO {level: "read"}]->(a)
  • Creates a user, a project, an application, and connects them with properties.


CREATE in Neo4j is like saying “always make this thing, even if it already exists”.
It’s used to insert new nodes and relationships into your graph.


1. CREATE Nodes

Syntax:

CREATE (alias:Label {propertyKey: value, ...})
  • alias → a temporary name used in your query (not stored in DB).

  • Label → the category/type of the node (User, Project, App, etc.).

  • {} → properties stored in the node.

Examples:

// Create a user node CREATE (u:User {name: "Alice", role: "Developer"})

✅ Creates one node:

(:User {name: "Alice", role: "Developer"})
// Create multiple nodes at once CREATE (:User {name: "Bob"}), (:Project {name: "ProjectX"})

✅ Creates:

(:User {name: "Bob"}) (:Project {name: "ProjectX"})

2. CREATE Relationships

Syntax:

CREATE (node1)-[:RELATIONSHIP_TYPE {properties...}]->(node2)
  • Relationships must connect two nodes.

  • RELATIONSHIP_TYPE is always in UPPERCASE by convention.

  • Properties are optional.

Example:

// Create nodes and relationship together CREATE (a:User {name: "Alice"})-[:WORKS_ON {since: 2023}]->(p:Project {name: "ProjectX"})

✅ Creates:

(:User {name: "Alice"}) -[:WORKS_ON {since: 2023}]-> (:Project {name: "ProjectX"})

3. Creating Relationships Between Existing Nodes

If the nodes already exist, you first match them, then create the relationship.

Example:

MATCH (a:User {name: "Alice"}), (p:Project {name: "ProjectX"}) CREATE (a)-[:WORKS_ON]->(p)

✅ Finds existing Alice and ProjectX and connects them.


4. CREATE vs MERGE

  • CREATE → Always creates new node/relationship, even if identical ones already exist → possible duplicates.

  • MERGE → Creates only if it doesn’t exist, otherwise reuses existing.

Case 1

MERGE (u:User {name: "Alice"})
  • Neo4j will search for a User node with name = "Alice".

  • If found → returns it.

  • If not found → creates a new node with only {name: "Alice"}.


Case 2

MERGE (u:User {name: "Alice", role: "Developer"})
  • Neo4j will search for a User node with both:

    • name = "Alice"

    • role = "Developer" 

  • If found → returns it.

  • If not found → creates a new node with {name: "Alice", role: "Developer"}.

⚠️ If an existing User node has name = "Alice" but no role property (or a different value), Neo4j will not consider it a match → it will create another node.
This can lead to duplicates if you’re not careful.


💡 Key point:
MERGE matches exactly the properties you specify.
If you want to match on one property but set others only if the node is new, you use ON CREATE SET or ON MATCH SET:

MERGE (u:User {name: "Alice"}) ON CREATE SET u.role = "Developer" ON MATCH SET u.lastSeen = date()
  • Matches on name only.

  • Adds role when creating.

  • Updates lastSeen when matching.

Comments