Skip to content

Mutations

GQL supports mutations for creating, updating and deleting graph data.

Creating Nodes

-- Create a node
INSERT (:Person {name: 'Alix', age: 30})

-- Create multiple nodes
INSERT (:Person {name: 'Alix'})
INSERT (:Person {name: 'Gus'})

-- Create with multiple labels
INSERT (:Person:Employee {name: 'Harm'})

Creating Edges

-- Create an edge between existing nodes
MATCH (a:Person {name: 'Alix'}), (b:Person {name: 'Gus'})
INSERT (a)-[:KNOWS]->(b)

-- Create edge with properties
MATCH (a:Person {name: 'Alix'}), (b:Person {name: 'Gus'})
INSERT (a)-[:KNOWS {since: 2020, strength: 'close'}]->(b)

Updating Properties

-- Set a property
MATCH (p:Person {name: 'Alix'})
SET p.age = 31

-- Set multiple properties
MATCH (p:Person {name: 'Alix'})
SET p.age = 31, p.city = 'New York'

-- Set from another property
MATCH (p:Person)
SET p.displayName = p.firstName + ' ' + p.lastName

Removing Properties

-- Remove a property
MATCH (p:Person {name: 'Alix'})
REMOVE p.temporaryField

-- Set to null (equivalent)
MATCH (p:Person {name: 'Alix'})
SET p.temporaryField = null

Map Property Operations

Replace All Properties

SET n = {map} replaces all existing properties with the map contents:

-- Replace all properties on a node
MATCH (p:Person {name: 'Alix'})
SET p = {name: 'Alix', age: 31, city: 'NYC'}
-- Any properties not in the map are removed

Merge Properties

SET n += {map} merges the map into existing properties, keeping properties not in the map:

-- Add or update properties, keep existing ones
MATCH (p:Person {name: 'Alix'})
SET p += {city: 'NYC', role: 'engineer'}
-- Existing properties like name and age are preserved

Label Operations

-- Add labels to a node
MATCH (p:Person {name: 'Alix'})
SET p:Employee:Manager

-- Remove a label
MATCH (p:Person {name: 'Alix'})
REMOVE p:Manager

Deleting Nodes

GQL supports two delete modes for nodes:

-- DELETE (or NODETACH DELETE): errors if the node has edges
MATCH (p:Person {name: 'Alix'})
DELETE p

-- Explicit NODETACH (same behavior as bare DELETE)
MATCH (p:Person {name: 'Alix'})
NODETACH DELETE p

-- DETACH DELETE: delete the node and all its connected edges
MATCH (p:Person {name: 'Alix'})
DETACH DELETE p

Tip

Use DELETE (without DETACH) when you want to ensure no edges are accidentally removed. The query will fail if the node still has connections, giving you a chance to handle them explicitly.

Deleting Edges

-- Delete specific edge
MATCH (a:Person {name: 'Alix'})-[r:KNOWS]->(b:Person {name: 'Gus'})
DELETE r

-- Delete all edges of a type from a node
MATCH (p:Person {name: 'Alix'})-[r:KNOWS]->()
DELETE r

DELETE with Expressions

DELETE targets can be general expressions, not just plain variables (GD04):

-- Delete using a property access expression
MATCH (n:Person)-[:MANAGES]->(dept:Department)
DELETE dept

-- Delete with a function expression
MATCH (n:Person)-[:HAS]->(item)
WHERE item.expired = true
DELETE item

UNWIND (List Expansion)

Expand a list into individual rows. Useful for batch operations.

-- Unwind a literal list
UNWIND [1, 2, 3] AS x
RETURN x

-- Unwind with parameters (Python: db.execute(query, {'names': ['Alix', 'Gus']}))
UNWIND $names AS name
RETURN name

-- Batch create edges from a parameter list
UNWIND $edges AS e
MATCH (a:Person {name: e.from}), (b:Person {name: e.to})
INSERT (a)-[:KNOWS]->(b)

FOR (GQL Standard List Iteration)

The GQL standard equivalent of UNWIND (ISO/IEC 39075 section 14.8).

-- Iterate over a list
FOR x IN [4, 5, 6]
RETURN x

-- Batch insert nodes
FOR person IN $people
INSERT (:Person {name: person.name, age: person.age})

FOR WITH ORDINALITY / OFFSET

Track the position of each element during iteration:

-- 1-based index (ORDINALITY)
FOR x IN ['a', 'b', 'c'] WITH ORDINALITY i
RETURN x, i
-- Returns: ('a', 1), ('b', 2), ('c', 3)

-- 0-based index (OFFSET)
FOR x IN ['a', 'b', 'c'] WITH OFFSET i
RETURN x, i
-- Returns: ('a', 0), ('b', 1), ('c', 2)

Merge (Upsert)

-- Create if not exists, match if exists
MERGE (p:Person {email: 'alix@example.com'})
SET p.lastSeen = timestamp()
RETURN p

-- Merge with different actions
MERGE (p:Person {email: 'alix@example.com'})
ON CREATE SET p.created = timestamp()
ON MATCH SET p.lastSeen = timestamp()
RETURN p