This page covers variable assignment, data manipulation, and output operations within stored procedures.
Declare and assign variables:
Procedure Body LanguageLET count = 0 LET name = 'Alice' LET threshold = 0.85 LET active = true LET nodes = [] LET data = {key: 'value', count: 42}
Reassign existing variables:
Procedure Body LanguageLET count = 0 FOR node IN SCAN(:Person) { count = count + 1 -- reassignment (without LET) } PRINT 'Total: ' || TOSTRING(count)
Assign the result of a subquery to a variable:
Procedure Body LanguageLET friends = (MATCH (p {_id: 'alice'})-[:KNOWS]->(f) RETURN f)
Assign properties to nodes that exist only during procedure execution. These are NOT persisted to storage:
Procedure Body Languagenode.visited = true node.tempScore = 0.5 node.level = depth
Use cases:
Procedure Body LanguageFOR node IN SCAN(:Person) { node.processed = false } FOR (node, depth) IN MATCH BFS (start)-[:KNOWS]->{1,5}(node) { node.distance = depth node.processed = true }
Query the graph within a procedure:
Procedure Body Language-- Find a specific node MATCH (p:Person {_id: $person_id}) -- Pattern matching MATCH (a:Person)-[:KNOWS]->(b:Person) -- With inline WHERE MATCH (n:Person WHERE n.age > 30) -- With standalone WHERE MATCH (a)-[:KNOWS]->(b) WHERE a.city = b.city
Results from MATCH bind variables for subsequent statements:
Procedure Body LanguageMATCH (p {_id: $person_id}) LET degree = OUT_DEGREE(p) PRINT 'Node ' || p._id || ' has degree ' || TOSTRING(degree)
Create nodes and edges:
Procedure Body Language-- Insert a node INSERT (:Person {_id: 'bob', name: 'Bob', age: 30}) -- Insert an edge between matched nodes MATCH (a {_id: 'alice'}) MATCH (b {_id: 'bob'}) INSERT (a)-[:KNOWS {since: 2024}]->(b)
Modify properties that are persisted to storage:
Procedure Body LanguageMATCH (n {_id: $node_id}) SET n.name = 'Updated Name' SET n.score = 0.95
Remove nodes and edges:
Procedure Body Language-- Delete a node (must have no edges) MATCH (n {_id: $node_id}) DELETE n -- Delete a node and all connected edges MATCH (n {_id: $node_id}) DETACH DELETE n
Return results from the procedure. Each RETURN statement adds a row to the output:
Procedure Body LanguageRETURN node._id AS node_id, score AS rank_score
Procedure Body LanguageRETURN name, age, score
Each iteration's RETURN adds a row:
GQLCREATE PROCEDURE list_people() RETURNS (name: STRING, age: INTEGER) AS { FOR node IN SCAN(:Person) { RETURN node.name AS name, node.age AS age -- Each iteration adds one row } }
GQLCREATE PROCEDURE init_data() RETURNS VOID AS { -- do work... RETURN -- explicit early exit (optional) }
Output debug messages to stderr:
Procedure Body LanguagePRINT 'Starting computation...' PRINT 'Count: ' || TOSTRING(count) PRINT 'Node ' || node._id || ' score = ' || TOSTRING(score)
PRINT is useful for:
Force commit buffered writes to storage:
Procedure Body Language-- After inserting many nodes FOR i IN RANGE(0, 10000) { INSERT (:DataPoint {_id: 'dp_' || TOSTRING(i), value: i}) IF i % 1000 = 0 { FLUSH -- commit every 1000 inserts } } FLUSH -- final flush
FLUSH is important when:
High-throughput batch insertion for loading data from procedures:
Procedure Body Language-- Insert nodes from a list of data -- Arguments: label, list of property maps LET node_data = [ {_id: 'n1', name: 'Alice', age: 30}, {_id: 'n2', name: 'Bob', age: 25} ] BATCH_INSERT_NODES('Person', node_data)
Procedure Body Language-- Insert edges from a list -- Arguments: edge type, list of edge specs LET edge_data = [ {_from: 'n1', _to: 'n2', weight: 0.8}, {_from: 'n2', _to: 'n1', weight: 0.6} ] BATCH_INSERT_EDGES('KNOWS', edge_data)
These batch operations are significantly faster than individual INSERT statements for large datasets.