UltipaDocs
Products
Solutions
Resources
Company
Start Free Trial
UltipaDocs
Start Free Trial
  • Introduction
  • GQL vs Other Languages
    • Overview
    • Node and Edge Patterns
    • Path Patterns
    • Quantified Paths
    • Questioned Paths
    • Shortest Paths
    • Cheapest Paths
    • K-Hop Traversal
    • Graph Patterns
    • Overview
    • Open Graph
    • Closed Graph
    • Graph Type
    • Constraints
    • Unique Identifiers
    • INSERT
    • INSERT OVERWRITE
    • UPSERT
    • MERGE
    • SET
    • REMOVE
    • DELETE
    • FOREACH
    • Query Composition
    • Result Table and Visualization
    • MATCH
    • OPTIONAL MATCH
    • FILTER
    • LET
    • FOR
    • ORDER BY
    • LIMIT
    • SKIP
    • CALL
    • RETURN
    • Composite Query
    • NEXT
    • All Functions
    • Element Functions
    • Path Functions
    • Aggregate Functions
    • Mathematical Functions
    • Trigonometric Functions
    • String Functions
    • List Functions
    • Datetime Functions
    • Spatial Functions
    • Null Functions
    • Utility Functions
    • Type Conversion Functions
    • Table Functions
    • AI & Vector Functions
    • Database Functions
  • Operators
  • Predicates
    • CASE
    • LET Value Expression
    • Value Query Expression
    • List Comprehension
    • Index
    • Full-text Index
    • Vector Index
  • Transactions
  • Triggers
  • Query Management
  • Execution Plan
  • Backup and Restore
    • Variables
    • Values and Types
    • Comments
    • Reserved Words
    • Naming Conventions
    • Syntactic Notation
  • GQL Conformance
  1. Docs
  2. /
  3. ISO GQL
  4. /
  5. Data Manipulation

FOREACH

Overview

The FOREACH statement iterates over a list and runs a write block once for each element.

NOTE

For row-by-row reading without writes, use the FOR statement instead. FOR unnests a list into rows of the intermediate result table; FOREACH does not produce rows and only performs side effects.

Syntax
<foreach statement> ::=
  "FOREACH" "(" <variable> "IN" <list value expression> "|" <foreach body> ")"

<foreach body> ::= <write statement> [ <write statement> ]...

Details

  • <variable> is bound to each element of <list value expression> in turn.
  • The body must consist of write statements: INSERT, MERGE, SET, REMOVE, DELETE, or a nested FOREACH.

Iterating a Literal List

Insert one Person node for each name in the list:

GQL
FOREACH (name IN ['Alice', 'Bob', 'Carol'] |
  INSERT (:Person {name: name})
)

Iterating a Range

Combined with the range() function, FOREACH can create a fixed number of related entities:

GQL
MATCH (start:Person {name: 'Alice'})
FOREACH (i IN range(1, 5) |
  MERGE (start)-[:Step {order: i}]->(:Checkpoint {num: i})
)

This creates checkpoints 1 through 5 and connects each one to Alice through a Step edge whose order equals the loop counter:

Iterating a List of Records

Each element can be a record. Reference its fields with the dot operator:

GQL
FOREACH (item IN [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}] |
  MERGE (p:Person {name: item.name})
  ON MATCH SET p.age = item.age
)

Updating Bound Variables

FOREACH can run after a MATCH to apply per-iteration updates to bound variables.

GQL
MATCH (p:Person {name: 'Alice'})
FOREACH (tag IN ['active', 'verified'] |
  SET p.tags = coalesce(p.tags, []) + [tag]
)

Use coalesce() to handle the case where the property does not yet exist. Without it, p.tags + [tag] evaluates to null on the first iteration and the assignment leaves p.tags unset. After the loop, tags of Alice is ['active', 'verified'].

Nested FOREACH

FOREACH blocks may be nested. The following statement creates one Team node per (department, level) pair:

GQL
FOREACH (dept IN ['Engineering', 'Sales'] |
  FOREACH (level IN [1, 2, 3] |
    MERGE (:Team {department: dept, level: level})
  )
)

The Cartesian product of the two lists produces 6 Team nodes:

departmentlevel
Engineering1
Engineering2
Engineering3
Sales1
Sales2
Sales3