Modifying Relationships
There is no “primary key” in a graph
Graph databases do not use primary keys like SQL tables do.
Each node has an internal ID, but it is not stable and should not be used as a functional identifier.
Instead, you can define a property as unique using a constraint:
CREATE CONSTRAINT person_name_unique
FOR (p:Person)
REQUIRE p.name IS UNIQUE;
This ensures that every Person node has a unique name value — effectively acting as a primary key.
Creating, updating and merging relationships
In Cypher, relationships can be created, updated, or merged just like nodes.
When modifying data, it is important to understand the difference between
CREATE, MATCH, and MERGE.
Creating new relationships
CREATE always creates something new — even if an identical relationship already exists.
MATCH (a:Person {name: "Alice"})
MATCH (b:Person {name: "Bob"})
CREATE (a)-[:FOLLOWS]->(b);
This command creates a new FOLLOWS relationship from Alice to Bob.
If such a relationship already exists, Cypher will create another one.
Matching existing relationships
MATCH only finds relationships that already exist.
It does not create or modify data.
MATCH (a:Person {name: "Alice"})-[r:FOLLOWS]->(b:Person {name: "Bob"})
RETURN r;
If no relationship exists between Alice and Bob, this query simply returns nothing.
Merging data safely
MERGE is a powerful command that combines the logic of MATCH and CREATE.
If the specified pattern exists, Neo4j reuses it; if not, it creates it.
This makes MERGE ideal for importing data or avoiding duplicates.
MATCH (a:Person {name: "Alice"})
MATCH (b:Person {name: "Bob"})
MERGE (a)-[:FOLLOWS]->(b);
If the FOLLOWS relationship already exists, it will not be created again.
If it does not exist, Neo4j will create it once.
Using MERGE with ON CREATE and ON MATCH
MERGE can also execute different actions depending on whether a pattern
was newly created or already existed.
MERGE (a:Person {name: "Alice"})
ON CREATE SET a.created_at = date()
ON MATCH SET a.last_seen = date();
Explanation:
ON CREATEruns only if the node is new.ON MATCHruns only if the node already existed.
This is useful for logging, synchronisation, or incremental data imports.
Merging relationships with properties
You can also use MERGE for relationships and set properties when they are first created.
MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"})
MERGE (a)-[r:FOLLOWS]->(b)
ON CREATE SET r.since = date("2025-01-01");
If the FOLLOWS relationship did not exist, it is created and timestamped.
If it already existed, no duplicate is made.
Merging on composite keys
Neo4j does not use composite primary keys, but you can simulate them with MERGE
by combining multiple properties in the same pattern.
MERGE (p:Purchase {order_id: 101, product_id: 55})
ON CREATE SET p.created_at = datetime();
This prevents duplicate records for the same (order_id, product_id) pair.
It is especially useful when importing transactional or event data.
Summary
| Command | Behaviour | When to use |
|---|---|---|
CREATE | Always creates a new node or relationship | When duplicates are acceptable |
MATCH | Only finds existing patterns | For reading or updating existing data |
MERGE | Finds or creates a pattern | For safe imports or idempotent updates |
Optional Visualization
graph TD
subgraph Actions
A[CREATE] -->|Always creates| X1((🔗 Relationship))
B[MATCH] -->|Finds existing only| X2((🔗 Relationship))
C[MERGE] -->|Creates if missing| X3((🔗 Relationship))
end
Explanation:
CREATE adds data blindly, MATCH only reads existing data, and MERGE intelligently decides whether to create or reuse existing elements.
🧠 Question:
Add a FOLLOWS relationship between Alice and Diana, but only if it does not already exist.
If it is created, set the property since to today’s date.