Skip to main content

Neo4j (standard.neo4j)

Concept Mapping

UQALNeo4j
TableNode Label
RowNode
FieldNode Property
RelationshipNo UQAL equivalent — use traversal syntax
get_tableMATCH (n:Label) RETURN n
get_rowMATCH (n:Label) RETURN n LIMIT 1
get_valueMATCH (n:Label) RETURN n.prop LIMIT 1
insert_rowCREATE (n:Label {…})
updateMATCH … SET
deleteMATCH … DETACH DELETE
create_viewNot supported (see below)
Native escapedb.cypher("…")

Connection Setup

# Local Neo4j
uqal add-connection graphdb standard.neo4j \
--host localhost \
--port 7687 \
--database neo4j \
--secret user neo4j \
--secret password password \
--no-interactive

# Neo4j AuraDB (cloud)
uqal add-connection auradb standard.neo4j \
--option uri "neo4j+s://abc123.databases.neo4j.io" \
--secret user neo4j \
--secret password MyAuraPassword \
--no-interactive

Options available in uqal_config.json:

KeyDefaultDescription
hostlocalhostNeo4j server host
port7687Bolt protocol port
databaseneo4jDatabase name
options.uriFull Bolt URI (overrides host/port)
options.connect_timeout10Connection timeout in seconds

Node Queries

Standard UQAL syntax works directly against Neo4j node labels:

# Get all User nodes
graphdb.User.get_table()

# Filter by property
graphdb.Order.get_table(where status = "open", fields id, customer, total)

# Single node
graphdb.User.get_row(where id = 42)

# Single value
graphdb.Order.get_value(where id = 42, field total)

Relationship Traversal

Graph relationships are the key feature that distinguishes Neo4j from relational and document databases. UQAL extends the query: block syntax with a relationship traversal expression.

Simple Traversal

In the where clause of an alias inside a query: block, write: SOURCE RELATIONSHIP_TYPE TARGET

let result = graphdb.query:
let u = table User
let o = table Order where u PLACED o
return u.name, o.id, o.total

Generates:

MATCH (u:`User`)-[:`PLACED`]->(o:`Order`)
RETURN u.name AS name, o.id AS id, o.total AS total

Traversal with Relationship Properties

Use square brackets to access properties stored on the relationship itself:

let result = graphdb.query:
let o = table Order
let p = table Product where o CONTAINS[quantity, unit_price] p
return o.id, p.name, quantity, unit_price

Generates:

MATCH (o:`Order`)-[r_p:`CONTAINS`]->(p:`Product`)
RETURN o.id AS id, p.name AS name, r_p.quantity AS quantity, r_p.unit_price AS unit_price

The bracketed names [quantity, unit_price] are the relationship property names. They appear as plain fields in the return clause and are resolved to the relationship variable automatically.

Multiple Hops

Chain multiple traversals to follow a path through the graph:

let result = graphdb.query:
let u = table User
let o = table Order where u PLACED o
let p = table Product where o CONTAINS[quantity] p
return u.name, p.name, quantity

Type Mapping

UQAL Core TypeNeo4j Type
intInteger
floatFloat
varcharString
boolBoolean
dateDate
datetimeDateTime
jsonStored as String
uuidStored as String

Views: Not Supported

Neo4j does not have a native view concept. create_view raises a NotImplementedError for this module.

What to use instead:

  • Save complex traversal queries as UQAL scripts (uqal script edit my_query)
  • Run them with uqal script run my_query
  • Or use native Cypher for reusable query patterns

Native Cypher

graphdb.cypher("MATCH (u:User)-[:PLACED]->(o:Order) RETURN u.name, count(o) AS order_count ORDER BY order_count DESC")

Blocked patterns (security validator):

PatternReason
LOAD CSVFile system access
CALL { … }Subquery (can bypass constraints)
DROPDestructive schema change
CREATE INDEXSchema modification
CREATE CONSTRAINTSchema modification
APOC.Requires explicit permission

Example

# Connect
uqal add-connection graphdb standard.neo4j --host localhost --database neo4j

# Sync schema (reads node labels and property keys)
uqal run "graphdb.sync_schema"

# Query all orders placed by a specific user
uqal run "
let result = graphdb.query:
let u = table User where u.name = 'Alice'
let o = table Order where u PLACED o
return u.name, o.id, o.total
"

# Traversal with relationship properties
uqal run "
let result = graphdb.query:
let o = table Order
let p = table Product where o CONTAINS[quantity, unit_price] p
return o.id, p.name, quantity, unit_price
"