Skip to content

Cypher Query Language

Uni supports a substantial subset of the OpenCypher query language, optimized for vectorized execution. This guide covers all supported syntax with practical examples.

Overview

Cypher is a declarative graph query language that uses ASCII-art patterns to describe graph structures:

// Pattern: (startNode)-[relationship]->(endNode)
MATCH (person:Person)-[:KNOWS]->(friend:Person)
WHERE person.age > 30
RETURN friend.name

Query Structure

A complete Cypher query follows this structure:

[MATCH clause]      -- Pattern matching
[WHERE clause]      -- Filtering
[WITH clause]       -- Intermediate processing
[RETURN clause]     -- Output projection
[ORDER BY clause]   -- Sorting
[SKIP/LIMIT clause] -- Pagination

Example Query

MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)
WHERE p.year >= 2020 AND a.affiliation = 'MIT'
RETURN p.title, a.name, p.year
ORDER BY p.year DESC
LIMIT 10

MATCH Clause

The MATCH clause specifies graph patterns to find.

Node Patterns

// Any node
MATCH (n)

// Node with label
MATCH (p:Paper)

// Node with multiple labels (future)
MATCH (n:Paper:Preprint)

// Node with variable binding
MATCH (paper:Paper)
RETURN paper.title

// Anonymous node (no variable)
MATCH (:Paper)-[:CITES]->(cited)
RETURN cited.title

Node Properties in Pattern

// Filter in pattern (equivalent to WHERE)
MATCH (p:Paper {year: 2023})
RETURN p.title

// Multiple properties
MATCH (p:Paper {year: 2023, venue: 'NeurIPS'})
RETURN p.title

Relationship Patterns

// Outgoing relationship
MATCH (a)-[:KNOWS]->(b)

// Incoming relationship
MATCH (a)<-[:KNOWS]-(b)

// Either direction
MATCH (a)-[:KNOWS]-(b)

// Any relationship type
MATCH (a)-[r]->(b)

// Relationship with variable
MATCH (p:Paper)-[c:CITES]->(cited:Paper)
RETURN c  // Access edge properties

Multi-Hop Patterns

// 2-hop path
MATCH (a:Paper)-[:CITES]->(b:Paper)-[:CITES]->(c:Paper)
RETURN a.title, b.title, c.title

// Chain multiple relationships
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)-[:AFFILIATED_WITH]->(u:University)
RETURN p.title, a.name, u.name

Variable-Length Paths

Variable-length path patterns allow traversing multiple hops in a single pattern.

// 1 to 3 hops
MATCH (a:Paper)-[:CITES*1..3]->(b:Paper)
RETURN a.title, b.title

// Exactly 2 hops
MATCH (a)-[:KNOWS*2]->(b)

// Any length (use with caution on large graphs)
MATCH (a)-[:KNOWS*]->(b)

// Zero or more hops
MATCH (a)-[:KNOWS*0..]->(b)

// With path variable
MATCH path = (a:Paper)-[:CITES*1..5]->(b:Paper)
WHERE a.title = 'Attention Is All You Need'
RETURN path, length(path) AS hops

WHERE Clause

The WHERE clause filters matched patterns.

Comparison Operators

// Equality
WHERE p.year = 2023

// Inequality
WHERE p.year <> 2020
WHERE p.year != 2020

// Comparison
WHERE p.year > 2020
WHERE p.year >= 2020
WHERE p.year < 2025
WHERE p.year <= 2025

Boolean Logic

// AND
WHERE p.year > 2020 AND p.venue = 'NeurIPS'

// OR
WHERE p.venue = 'NeurIPS' OR p.venue = 'ICML'

// NOT
WHERE NOT p.is_retracted

// Parentheses for grouping
WHERE (p.year > 2020 AND p.venue = 'NeurIPS') OR p.citations > 1000

NULL Handling

// Check for NULL
WHERE p.doi IS NULL
WHERE p.doi IS NOT NULL

// COALESCE (use default if NULL)
RETURN COALESCE(p.nickname, p.name) AS display_name

String Operations

// Starts with
WHERE p.title STARTS WITH 'Attention'

// Ends with
WHERE p.title ENDS WITH 'Networks'

// Contains (uses JSON FTS index if available)
WHERE p.title CONTAINS 'Transformer'

// Full-text search on JSON document column (requires JSON FTS index)
WHERE a._doc CONTAINS 'graph database'

// Path-specific JSON FTS search
WHERE a._doc.title CONTAINS 'graph'

// Regular expression (future)
WHERE p.title =~ '.*Transform.*'

Note: The CONTAINS operator is automatically routed to JSON FTS indexes when the column has an FTS index, enabling BM25-based full-text search with relevance ranking.

List Operations

// IN list
WHERE p.venue IN ['NeurIPS', 'ICML', 'ICLR']

// NOT IN
WHERE p.venue NOT IN ['Workshop', 'Demo']

Property Existence

// Check if property exists
WHERE p.abstract IS NOT NULL

// In pattern
WHERE EXISTS(p.doi)

RETURN Clause

The RETURN clause specifies output columns.

Basic Projections

// Single property
RETURN p.title

// Multiple properties
RETURN p.title, p.year, p.venue

// All properties (*)
RETURN p.*

// Entire node
RETURN p

Aliases

// AS keyword
RETURN p.title AS paper_title, a.name AS author_name

// Expression aliases
RETURN p.year + 1 AS next_year

Expressions

// Arithmetic
RETURN p.citations * 2 AS double_citations

// String concatenation
RETURN p.title + ' (' + p.venue + ')' AS formatted

// Conditional (CASE)
RETURN CASE
  WHEN p.citations > 1000 THEN 'High Impact'
  WHEN p.citations > 100 THEN 'Medium Impact'
  ELSE 'Low Impact'
END AS impact_level

DISTINCT

// Remove duplicates
RETURN DISTINCT p.venue

// Distinct combinations
RETURN DISTINCT p.venue, p.year

Aggregations

Uni supports standard aggregation functions.

Aggregation Functions

Function Description Example
COUNT(*) Count all rows RETURN COUNT(*)
COUNT(x) Count non-null values RETURN COUNT(p.doi)
COUNT(DISTINCT x) Count distinct values RETURN COUNT(DISTINCT p.venue)
SUM(x) Sum numeric values RETURN SUM(p.citations)
AVG(x) Average RETURN AVG(p.citations)
MIN(x) Minimum RETURN MIN(p.year)
MAX(x) Maximum RETURN MAX(p.year)
COLLECT(x) Collect into list RETURN COLLECT(p.title)

Implicit Grouping

Non-aggregated columns become GROUP BY keys:

// Group by venue, count papers per venue
MATCH (p:Paper)
RETURN p.venue, COUNT(p) AS paper_count
ORDER BY paper_count DESC

Aggregation Examples

// Count papers per author
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)
RETURN a.name, COUNT(p) AS papers, AVG(p.citations) AS avg_citations
ORDER BY papers DESC

// Most cited papers per venue
MATCH (p:Paper)
RETURN p.venue, MAX(p.citations) AS top_citations, COUNT(p) AS total
ORDER BY top_citations DESC

Window Functions

Window functions perform calculations across a set of rows related to the current row, without collapsing results like aggregations.

Basic Syntax

function_name(args) OVER (
  [PARTITION BY partition_expr, ...]
  [ORDER BY order_expr [ASC|DESC], ...]
)

Supported Window Functions

Function Description Example
row_number() Sequential row number row_number() OVER (ORDER BY p.year)
rank() Rank with gaps for ties rank() OVER (ORDER BY p.citations DESC)
dense_rank() Rank without gaps dense_rank() OVER (ORDER BY p.citations DESC)
sum() Running sum sum(p.citations) OVER (ORDER BY p.year)
avg() Running average avg(p.citations) OVER (PARTITION BY p.venue)
count() Running count count(*) OVER (PARTITION BY p.venue)
min() / max() Running min/max max(p.citations) OVER (PARTITION BY p.author)

Examples

Ranking within partitions:

MATCH (p:Paper)
RETURN p.title, p.venue, p.citations,
       rank() OVER (PARTITION BY p.venue ORDER BY p.citations DESC) AS venue_rank
ORDER BY p.venue, venue_rank

Running totals:

MATCH (p:Paper)
WHERE p.author = 'Alice'
RETURN p.title, p.year, p.citations,
       sum(p.citations) OVER (ORDER BY p.year) AS cumulative_citations
ORDER BY p.year

Top N per group:

MATCH (p:Paper)
WITH p, row_number() OVER (PARTITION BY p.venue ORDER BY p.citations DESC) AS rn
WHERE rn <= 3
RETURN p.venue, p.title, p.citations
ORDER BY p.venue, p.citations DESC


Scalar Functions

Uni provides a comprehensive set of scalar functions for data transformation.

String Functions

Function Description Example
toUpper(s) / upper(s) Convert to uppercase RETURN toUpper('hello')'HELLO'
toLower(s) / lower(s) Convert to lowercase RETURN toLower('HELLO')'hello'
trim(s) Remove leading/trailing whitespace RETURN trim(' hi ')'hi'
ltrim(s) Remove leading whitespace RETURN ltrim(' hi')'hi'
rtrim(s) Remove trailing whitespace RETURN rtrim('hi ')'hi'
substring(s, start, [len]) Extract substring RETURN substring('hello', 1, 3)'ell'
left(s, n) First n characters RETURN left('hello', 2)'he'
right(s, n) Last n characters RETURN right('hello', 2)'lo'
reverse(s) Reverse string RETURN reverse('hello')'olleh'
replace(s, old, new) Replace occurrences RETURN replace('hello', 'l', 'x')'hexxo'
split(s, delim) Split into list RETURN split('a,b,c', ',')['a','b','c']
lpad(s, len, [pad]) Pad left to length RETURN lpad('5', 3, '0')'005'
rpad(s, len, [pad]) Pad right to length RETURN rpad('5', 3, '0')'500'

Math Functions

Function Description Example
abs(n) Absolute value RETURN abs(-5)5
ceil(n) Round up RETURN ceil(4.2)5
floor(n) Round down RETURN floor(4.8)4
round(n) Round to nearest RETURN round(4.5)5
sqrt(n) Square root RETURN sqrt(16)4
sign(n) Sign (-1, 0, 1) RETURN sign(-5)-1
log(n) Natural logarithm RETURN log(2.718)~1
log10(n) Base-10 logarithm RETURN log10(100)2
exp(n) e^n RETURN exp(1)~2.718
power(base, exp) / pow(base, exp) Exponentiation RETURN power(2, 3)8
sin(n), cos(n), tan(n) Trigonometric RETURN sin(0)0

List Functions

Function Description Example
size(list) Length of list/string/map RETURN size([1,2,3])3
head(list) First element RETURN head([1,2,3])1
tail(list) All but first element RETURN tail([1,2,3])[2,3]
last(list) Last element RETURN last([1,2,3])3
keys(map) Keys of a map RETURN keys({a:1, b:2})['a','b']
range(start, end, [step]) Generate number sequence RETURN range(1, 5)[1,2,3,4,5]

Path Functions

Function Description Example
length(path) Number of relationships in path RETURN length(path)
nodes(path) List of nodes in path RETURN nodes(path)
relationships(path) List of relationships in path RETURN relationships(path)

Type Conversion Functions

Function Description Example
toInteger(x) Convert to integer RETURN toInteger('42')42
toFloat(x) Convert to float RETURN toFloat('3.14')3.14
toString(x) Convert to string RETURN toString(42)'42'
toBoolean(x) Convert to boolean RETURN toBoolean('true')true

Null Handling Functions

Function Description Example
coalesce(x, y, ...) First non-null value RETURN coalesce(null, 'default')'default'
nullif(a, b) Return null if a = b RETURN nullif(5, 5)null

Example Usage

// String manipulation
MATCH (p:Paper)
RETURN toUpper(p.title) AS upper_title,
       substring(p.abstract, 0, 100) AS abstract_preview

// Math operations
MATCH (p:Paper)
RETURN p.title, round(p.citations / 10.0) * 10 AS rounded_citations

// List operations
MATCH (a:Author)
WHERE size(a.affiliations) > 1
RETURN a.name, head(a.affiliations) AS primary_affiliation

// Type conversion
MATCH (p:Paper)
WHERE toInteger(p.year_str) > 2020
RETURN p.title

ORDER BY, SKIP, LIMIT

Sorting

// Ascending (default)
ORDER BY p.year

// Descending
ORDER BY p.year DESC

// Multiple columns
ORDER BY p.year DESC, p.title ASC

// By alias
RETURN p.title, p.citations AS cites
ORDER BY cites DESC

Pagination

// First 10 results
LIMIT 10

// Skip first 20, take next 10
SKIP 20
LIMIT 10

// Combined
RETURN p.title
ORDER BY p.year DESC
SKIP 100
LIMIT 25

CREATE Clause

Create new nodes and relationships.

Creating Nodes

// Simple node
CREATE (p:Paper {title: 'My Paper'})

// With properties
CREATE (p:Paper {
  title: 'New Research',
  year: 2024,
  venue: 'ArXiv',
  citations: 0
})
RETURN p

// Multiple nodes
CREATE (a:Author {name: 'Alice'}), (b:Author {name: 'Bob'})

Creating Relationships

// Between existing nodes
MATCH (p:Paper {title: 'Paper A'}), (a:Author {name: 'Alice'})
CREATE (p)-[:AUTHORED_BY {position: 1}]->(a)

// Create node and relationship together
CREATE (p:Paper {title: 'New Paper'})-[:AUTHORED_BY]->(a:Author {name: 'New Author'})

Returning Created Elements

CREATE (p:Paper {title: 'My Paper', year: 2024})
RETURN p.title, p.year

WITH Clause

The WITH clause chains query parts together.

Intermediate Processing

// Filter after aggregation
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)
WITH a, COUNT(p) AS paper_count
WHERE paper_count > 5
RETURN a.name, paper_count

Subquery-like Behavior

// First find top authors, then their papers
MATCH (a:Author)<-[:AUTHORED_BY]-(p:Paper)
WITH a, COUNT(p) AS papers
ORDER BY papers DESC
LIMIT 10
MATCH (a)<-[:AUTHORED_BY]-(recent:Paper)
WHERE recent.year >= 2022
RETURN a.name, recent.title

UNWIND Clause

Expand a list into individual rows.

// Expand literal list
UNWIND [1, 2, 3] AS num
RETURN num

// Expand list property
MATCH (p:Paper)
UNWIND p.keywords AS keyword
RETURN keyword, COUNT(*) AS usage
ORDER BY usage DESC

// Create multiple from list
UNWIND ['Alice', 'Bob', 'Charlie'] AS name
CREATE (a:Author {name: name})

CALL Clause (Procedures)

Invoke built-in procedures.

// Basic vector search
CALL db.idx.vector.query('Paper', 'embedding', $query_vector, 10)
YIELD node, distance
RETURN node.title, distance

// With threshold
CALL db.idx.vector.query('Paper', 'embedding', $query_vector, 100, 0.3)
YIELD node, distance
WHERE distance < 0.2
RETURN node.title, distance

Schema Introspection

// List labels
CALL db.labels()
YIELD label
RETURN label

// List relationship types
CALL db.relationshipTypes()
YIELD relationshipType
RETURN relationshipType

// List indexes
CALL db.indexes()
YIELD name, type, labelsOrTypes, properties
RETURN *

Index Management

Create Indexes

// Scalar index
CREATE INDEX ON :Paper(year)

// Named index
CREATE INDEX paper_year FOR (p:Paper) ON (p.year)

// Vector index
CREATE VECTOR INDEX paper_embeddings
FOR (p:Paper) ON p.embedding
OPTIONS {index_type: 'hnsw', metric: 'cosine'}

// JSON Full-Text index
CREATE JSON FULLTEXT INDEX article_fts
FOR (a:Article) ON _doc
OPTIONS {with_positions: true}

Drop Indexes

DROP INDEX paper_year

Show Indexes

SHOW INDEXES

Query Parameters

Use parameters to avoid injection and improve plan caching.

Parameter Syntax

// In query
MATCH (p:Paper)
WHERE p.year = $year AND p.venue = $venue
RETURN p.title

CLI Usage

uni query "MATCH (p:Paper) WHERE p.year = \$year RETURN p" \
    --params '{"year": 2023}' \
    --path ./storage

Session Variables

Session variables provide scoped context that's automatically available in all queries within a session. This is ideal for multi-tenant applications.

Creating a Session

// Rust API
let session = db.session()
    .set("tenant_id", "acme-corp")
    .set("user_id", "user-123")
    .set("granted_tags", vec!["public", "team:eng"])
    .build();

Using Session Variables

Access session variables with the $session. prefix:

// Automatic tenant filtering
MATCH (d:Document)
WHERE d.tenant_id = $session.tenant_id
RETURN d.title

// Multiple session variables
MATCH (e:Event)
WHERE e.tenant_id = $session.tenant_id
  AND e.created_by = $session.user_id
RETURN e

// Combining session variables with query parameters
MATCH (d:Document)
WHERE d.tenant_id = $session.tenant_id
  AND d.status = $status
RETURN d

Session Variable Benefits

Benefit Description
Reduced boilerplate No need to pass tenant_id to every query
Security Variables are immutable after session creation
Consistency Same context applied to all queries in session
Multi-tenancy Natural pattern for SaaS applications

Session Queries vs Regular Queries

// Without session (repetitive)
db.query_with("MATCH (d:Document) WHERE d.tenant = $t RETURN d")
    .param("t", "acme")
    .fetch_all().await?;

// With session (cleaner)
let session = db.session().set("tenant", "acme").build();
session.query("MATCH (d:Document) WHERE d.tenant = $session.tenant RETURN d").await?;

Temporal Queries

Uni provides functions for querying temporal (time-based) data with validity ranges.

validAt Function

Check if a node or edge was valid at a specific point in time:

// Basic validAt usage
MATCH (e:Event)
WHERE uni.validAt(e, 'valid_from', 'valid_to', datetime($time))
RETURN e.name, e.valid_from, e.valid_to

Parameters: - e: Node or edge to check - 'valid_from': Property name for start time - 'valid_to': Property name for end time - datetime($time): Point in time to check

Semantics: valid_from <= time < valid_to (half-open interval)

VALID_AT Macro

For convenience, use the VALID_AT macro with default property names:

// Macro form (uses 'valid_from' and 'valid_to' by default)
MATCH (e:Event)
WHERE e VALID_AT datetime('2024-06-15T12:00:00Z')
RETURN e.name

Custom Property Names

Specify custom property names if your schema differs:

// With custom property names
MATCH (c:Contract)
WHERE c VALID_AT(datetime($check_time), 'start_date', 'end_date')
RETURN c.name, c.value

Temporal Query Patterns

Find currently valid records:

MATCH (e:Employee)
WHERE uni.validAt(e, 'hire_date', 'termination_date', datetime())
RETURN e.name, e.department

Find records valid at a historical point:

MATCH (p:Price)
WHERE p.product_id = $product_id
  AND uni.validAt(p, 'effective_from', 'effective_to', datetime('2024-01-01'))
RETURN p.amount

Temporal edges:

MATCH (e:Employee)-[r:WORKS_IN]->(d:Department)
WHERE uni.validAt(r, 'start_date', 'end_date', datetime($as_of_date))
RETURN e.name, d.name

Open-ended validity (NULL end date):

// Records with NULL valid_to are considered currently valid
MATCH (m:Membership)
WHERE m.valid_to IS NULL
  OR m.valid_to > datetime()
RETURN m

DELETE Clause

Remove nodes and relationships from the graph.

Deleting Relationships

// Delete a specific relationship
MATCH (a:Author)-[r:AUTHORED]->(p:Paper)
WHERE a.name = 'Alice' AND p.title = 'Old Paper'
DELETE r

// Delete all relationships of a type
MATCH ()-[r:DEPRECATED]->()
DELETE r

Deleting Nodes

// Delete a node (must have no relationships)
MATCH (p:Paper {title: 'Deleted Paper'})
DELETE p

// Delete node and all its relationships (DETACH)
MATCH (p:Paper {title: 'Deleted Paper'})
DETACH DELETE p

// Delete multiple nodes
MATCH (p:Paper)
WHERE p.year < 1990
DETACH DELETE p

Conditional Deletion

// Delete only if condition is met
MATCH (p:Paper)
WHERE p.citations = 0 AND p.year < 2000
DETACH DELETE p
RETURN COUNT(*) AS deleted_count

UNION Clause

Combine results from multiple queries.

UNION (Distinct)

// Combine results, removing duplicates
MATCH (a:Author {affiliation: 'MIT'})
RETURN a.name AS name
UNION
MATCH (a:Author {affiliation: 'Stanford'})
RETURN a.name AS name

UNION ALL (Keep Duplicates)

// Combine results, keeping all rows
MATCH (p:Paper)-[:CITES]->(:Paper {title: 'Paper A'})
RETURN p.title AS title
UNION ALL
MATCH (p:Paper)-[:CITES]->(:Paper {title: 'Paper B'})
RETURN p.title AS title

Multi-way UNION

// Combine multiple queries
MATCH (a:Author) WHERE a.h_index > 50
RETURN a.name AS name, 'high_impact' AS category
UNION
MATCH (a:Author) WHERE a.papers > 100
RETURN a.name AS name, 'prolific' AS category
UNION
MATCH (a:Author) WHERE a.citations > 10000
RETURN a.name AS name, 'highly_cited' AS category

WITH RECURSIVE Clause

Execute recursive queries using Common Table Expressions (CTEs).

Basic Recursive Query

// Find all transitive citations (papers cited by cited papers)
WITH RECURSIVE citation_chain AS (
  // Base case: direct citations
  MATCH (p:Paper {title: 'Root Paper'})-[:CITES]->(cited:Paper)
  RETURN cited
  UNION
  // Recursive case: citations of citations
  MATCH (c:citation_chain)-[:CITES]->(next:Paper)
  RETURN next
)
MATCH (p:citation_chain)
RETURN p.title

Recursive Path Finding

// Find all ancestors in a hierarchy
WITH RECURSIVE ancestors AS (
  MATCH (n:Category {name: 'Machine Learning'})
  RETURN n
  UNION
  MATCH (a:ancestors)-[:PARENT]->(parent:Category)
  RETURN parent
)
MATCH (a:ancestors)
RETURN a.name AS category_hierarchy

EXPLAIN Clause

Inspect the query execution plan without running the query.

Basic EXPLAIN

// Show query plan
EXPLAIN MATCH (p:Paper)-[:CITES]->(cited:Paper)
WHERE p.year > 2020
RETURN cited.title, COUNT(*) AS citation_count
ORDER BY citation_count DESC
LIMIT 10

Understanding the Plan

The EXPLAIN output shows: - Scan operations: How data is accessed (index scan, full scan) - Filter operations: Where predicates are applied - Join operations: How patterns are matched - Aggregation: Grouping and aggregation steps - Sort/Limit: Final ordering and pagination - Index usage: Which indexes are used and why - Cost estimates: Estimated rows and query cost

EXPLAIN Output Example

Plan:
├─ Scan: Paper
│  ├─ Filter: year > 2020
│  │  └─ Index: paper_year_btree (BTREE) ✓
│  ├─ Estimated rows: 500
│  └─ Cost: 12.5
├─ Expand: CITES (OUTGOING)
│  ├─ Estimated paths: 2500
│  └─ Cost: 125.0
└─ Target: Paper
   └─ Estimated rows: 2500

Index Usage:
  ✓ Paper.year → paper_year_btree (BTREE)
  ✗ Paper.venue → paper_venue_idx (not in filter)

Total estimated cost: 137.5

PROFILE Clause

Execute the query with runtime statistics collection.

Basic PROFILE

// Execute and collect statistics
PROFILE MATCH (p:Paper)-[:CITES]->(cited:Paper)
WHERE p.year > 2020
RETURN cited.title, COUNT(*) AS citation_count
ORDER BY citation_count DESC
LIMIT 10

PROFILE Output

PROFILE returns detailed execution metrics:

Execution Profile:
├─ Scan: Paper
│  ├─ Actual rows: 423
│  ├─ Time: 12.3ms
│  └─ Index hits: 423
├─ Expand: CITES
│  ├─ Actual paths: 1892
│  └─ Time: 45.6ms
└─ Project
   ├─ Actual rows: 1892
   └─ Time: 1.2ms

Summary:
  Total time: 59.1ms
  Peak memory: 2.4MB
  Rows returned: 1892

Using PROFILE for Optimization

// Compare two query approaches
PROFILE MATCH (a:Author)-[:AUTHORED]->(p:Paper)
WHERE a.name = 'Alice' AND p.year > 2020
RETURN p.title

// vs

PROFILE MATCH (p:Paper)
WHERE p.year > 2020
MATCH (a:Author {name: 'Alice'})-[:AUTHORED]->(p)
RETURN p.title

Common Query Patterns

Find Connected Nodes

MATCH (start:Paper {title: 'Attention Is All You Need'})
MATCH (start)-[:CITES]->(cited)
RETURN cited.title, cited.year
ORDER BY cited.year DESC

Bidirectional Relationships

// Papers that cite each other
MATCH (a:Paper)-[:CITES]->(b:Paper)-[:CITES]->(a)
RETURN a.title, b.title

Shortest Path (Future)

// Shortest path between two nodes
MATCH path = shortestPath((a:Author {name: 'Alice'})-[:COAUTHOR*]-(b:Author {name: 'Bob'}))
RETURN path

Degree Counting

// Count outgoing relationships
MATCH (p:Paper)-[c:CITES]->()
RETURN p.title, COUNT(c) AS out_degree
ORDER BY out_degree DESC

Top-K with Ties

MATCH (p:Paper)
WITH p, p.citations AS cites
ORDER BY cites DESC
LIMIT 10
RETURN p.title, cites

Graph Algorithms

Uni provides 36 high-performance graph algorithms available via the algo namespace.

Centrality Algorithms

Algorithm Procedure Description
PageRank algo.pageRank Importance based on incoming links
Betweenness algo.betweenness Nodes on shortest paths
Closeness algo.closeness Average distance to all nodes
Degree Centrality algo.degreeCentrality Connection count
Harmonic Centrality algo.harmonicCentrality Harmonic mean distance
Eigenvector Centrality algo.eigenvectorCentrality Influence via neighbors
Katz Centrality algo.katzCentrality Weighted path influence
// PageRank
CALL algo.pageRank(['Paper'], ['CITES'])
YIELD nodeId, score
RETURN nodeId, score
ORDER BY score DESC

// Betweenness Centrality
CALL algo.betweenness(['Author'], ['COAUTHOR'], true, 100)
YIELD nodeId, score

// Closeness Centrality
CALL algo.closeness(['Station'], ['CONNECTS'])
YIELD nodeId, score

Community Detection Algorithms

Algorithm Procedure Description
Louvain algo.louvain Modularity-based community detection
Label Propagation algo.labelPropagation Fast community detection
WCC algo.wcc Weakly connected components
SCC algo.scc Strongly connected components
K-Core algo.kCore K-core decomposition
Triangle Count algo.triangleCount Count triangles per node
// Louvain
CALL algo.louvain(['User'], ['INTERACTS'])
YIELD nodeId, communityId

// Label Propagation
CALL algo.labelPropagation(['User'], ['INTERACTS'])
YIELD nodeId, communityId

// Weakly Connected Components
CALL algo.wcc(['User'], ['INTERACTS'])
YIELD nodeId, componentId

// Strongly Connected Components
CALL algo.scc(['Task'], ['DEPENDS_ON'])
YIELD nodeId, componentId

// K-Core Decomposition
CALL algo.kCore(['User'], ['FRIEND'], 3)
YIELD nodeId, coreNumber

// Triangle Count
CALL algo.triangleCount(['User'], ['FRIEND'])
YIELD nodeId, triangleCount

Path Finding Algorithms

Algorithm Procedure Description
Dijkstra algo.dijkstra Shortest weighted path
Bellman-Ford algo.bellmanFord Shortest path with negative weights
A* algo.astar Heuristic shortest path
Bidirectional Dijkstra algo.bidirectionalDijkstra Two-way shortest path
K-Shortest Paths algo.kShortestPaths Multiple shortest paths
All Simple Paths algo.allSimplePaths All paths between nodes
APSP algo.allPairsShortestPath All pairs shortest path
// Dijkstra shortest path
CALL algo.dijkstra(['Station'], ['CONNECTS'], $startId, $endId, 'distance')
YIELD path, cost

// K-Shortest Paths
CALL algo.kShortestPaths(['Station'], ['CONNECTS'], $startId, $endId, 5)
YIELD path, cost

// All Pairs Shortest Path
CALL algo.allPairsShortestPath(['Station'], ['CONNECTS'])
YIELD sourceNodeId, targetNodeId, distance

Similarity & Traversal Algorithms

Algorithm Procedure Description
Node Similarity algo.nodeSimilarity Jaccard similarity
Random Walk algo.randomWalk Random graph traversal
Maximal Cliques algo.maximalCliques Find all maximal cliques
Graph Coloring algo.graphColoring Vertex coloring
// Node Similarity (Jaccard)
CALL algo.nodeSimilarity(['Product'], ['PURCHASED'])
YIELD node1, node2, similarity

// Random Walk
CALL algo.randomWalk(['Page'], ['LINKS'], 10, 5)
YIELD path

Structural Analysis Algorithms

Algorithm Procedure Description
Topological Sort algo.topologicalSort DAG ordering
Cycle Detection algo.cycleDetection Find cycles
Bipartite Check algo.bipartiteCheck Test bipartiteness
Bridges algo.bridges Find bridge edges
Articulation Points algo.articulationPoints Find cut vertices
Elementary Circuits algo.elementaryCircuits Find all simple cycles
// Topological sort (for DAGs)
CALL algo.topologicalSort(['Task'], ['DEPENDS_ON'])
YIELD nodeId, order

// Find articulation points
CALL algo.articulationPoints(['Router'], ['CONNECTS'])
YIELD nodeId

Flow & Matching Algorithms

Algorithm Procedure Description
Maximum Matching algo.maxMatching Maximum cardinality matching
Minimum Spanning Tree algo.mst MST using Prim/Kruskal
Dinic's Algorithm algo.dinic Maximum flow
Ford-Fulkerson algo.fordFulkerson Maximum flow
// Minimum Spanning Tree
CALL algo.mst(['City'], ['ROAD'], 'distance')
YIELD edge, cost

// Maximum Matching
CALL algo.maxMatching(['Worker', 'Job'], ['CAN_DO'])
YIELD node1, node2

Schema DDL

Uni supports Data Definition Language (DDL) statements for managing schema.

Create Label (Vertex Type)

// Create a label with properties
CREATE LABEL Paper (
  title STRING NOT NULL,
  year INT32,
  abstract STRING,
  embedding VECTOR(768)
)

// Create label with default values
CREATE LABEL Author (
  name STRING NOT NULL,
  h_index INT32 DEFAULT 0,
  active BOOLEAN DEFAULT true
)

Create Edge Type

// Create edge type with source/destination constraints
CREATE EDGE TYPE AUTHORED FROM Author TO Paper (
  position INT32,
  corresponding BOOLEAN DEFAULT false
)

// Edge type between multiple label types
CREATE EDGE TYPE COLLABORATES FROM Author TO Author (
  papers_count INT32
)

Alter Schema

// Add a property to an existing label
ALTER LABEL Paper ADD abstract STRING

// Drop a property
ALTER LABEL Paper DROP deprecated_field

// Rename a property
ALTER LABEL Paper RENAME old_name TO new_name

Drop Schema Elements

// Drop a label (must have no vertices)
DROP LABEL TempLabel

// Drop an edge type
DROP EDGE TYPE OLD_RELATIONSHIP

Constraints

Define and manage data integrity constraints.

Create Constraints

// Unique constraint
CREATE CONSTRAINT paper_doi_unique
FOR (p:Paper) REQUIRE p.doi IS UNIQUE

// Existence constraint (property must be present)
CREATE CONSTRAINT author_name_exists
FOR (a:Author) REQUIRE a.name IS NOT NULL

// Check constraint (custom validation)
CREATE CONSTRAINT paper_year_valid
FOR (p:Paper) REQUIRE p.year >= 1900 AND p.year <= 2100

Show Constraints

// List all constraints
SHOW CONSTRAINTS

// Filter by label
SHOW CONSTRAINTS FOR :Paper

Drop Constraints

DROP CONSTRAINT paper_doi_unique

Database Management

Administrative commands and procedures for database maintenance.

BACKUP

Create a backup of the database to a specified destination.

// Backup to local path
BACKUP TO './backups/backup_2026_01_17'

// Backup to S3
BACKUP TO 's3://my-bucket/backups/backup_2026_01_17'

// Backup with options
BACKUP TO './backups/full' WITH incremental = false, compress = true

VACUUM

Reclaim storage space by removing deleted data and compacting files.

// Perform vacuum operation
VACUUM

// Note: VACUUM may take time on large databases
// and temporarily increases I/O load

CHECKPOINT

Force a checkpoint to flush all pending writes to durable storage.

// Force checkpoint
CHECKPOINT

// Useful before taking external backups
// or when durability guarantee is needed immediately

Compaction

// Trigger storage compaction
CALL db.compact()
YIELD fragmentsCompacted, bytesReclaimed, duration

// Check compaction status
CALL db.compactionStatus()
YIELD status, progress, estimatedRemaining

Snapshots

// Create a named snapshot
CALL db.snapshot.create('before_migration')
YIELD name, created, size

// List available snapshots
CALL db.snapshot.list()
YIELD name, created, size

// Restore to a snapshot
CALL db.snapshot.restore('before_migration')

Schema Introspection

// List all labels
CALL db.labels()
YIELD label, propertyCount, nodeCount, indexCount
RETURN label, nodeCount

// List all relationship types
CALL db.relationshipTypes()
YIELD type, sourceLabels, targetLabels, propertyCount
RETURN type

// List all edge types (alias)
CALL db.edgeTypes()
YIELD type, sourceLabels, targetLabels, propertyCount

// List all indexes
CALL db.indexes()
YIELD name, type, label, properties, state
WHERE type = 'VECTOR'
RETURN name, label

// List all constraints
CALL db.constraints()
YIELD name, type, label, properties, enabled
RETURN name, type

// Get detailed label info
CALL db.schema.labelInfo('Paper')
YIELD property, dataType, nullable, indexed, unique
RETURN property, dataType

Schema DDL Procedures

Create and modify schema at runtime via procedures:

// Create a new label
CALL db.createLabel('Product', {
  properties: {
    name: { type: 'STRING', nullable: false },
    price: { type: 'FLOAT64' },
    embedding: { type: 'VECTOR', dimensions: 128 }
  }
})

// Create an edge type
CALL db.createEdgeType('PURCHASED', ['Customer'], ['Product'], {
  properties: {
    quantity: { type: 'INT32' },
    timestamp: { type: 'TIMESTAMP' }
  }
})

// Create an index
CALL db.createIndex('Product', 'name', { type: 'BTREE' })

// Create a vector index
CALL db.createIndex('Product', 'embedding', {
  type: 'VECTOR',
  metric: 'cosine',
  index_type: 'hnsw',
  m: 16,
  ef_construction: 200
})

// Create a constraint
CALL db.createConstraint('Product', 'UNIQUE', ['sku'])

// Drop operations
CALL db.dropLabel('TempLabel')
CALL db.dropEdgeType('OLD_RELATIONSHIP')
CALL db.dropIndex('Product', 'old_index')
CALL db.dropConstraint('Product', 'constraint_name')

CRDT Properties

Uni supports CRDT (Conflict-free Replicated Data Type) properties for distributed, eventually-consistent data. CRDT properties can be defined in the schema and manipulated via Cypher.

Schema Definition

Define CRDT properties in your schema:

{
  "properties": {
    "Paper": {
      "title": { "type": "String", "nullable": false },
      "view_count": { "type": "Crdt", "crdt_type": "GCounter" },
      "tags": { "type": "Crdt", "crdt_type": "ORSet" },
      "metadata": { "type": "Crdt", "crdt_type": "LWWMap" }
    }
  }
}

Supported CRDT Types

Type Description Cypher Operations
GCounter Grow-only counter Increment only
GSet Grow-only set Add only
ORSet Add/remove set (add-wins) Add, remove
LWWRegister Single value (last-writer-wins) Set value
LWWMap Key-value map (per-key LWW) Put, remove keys
Rga Ordered sequence Insert, delete at position

Querying CRDT Properties

// Read CRDT values (returns materialized value)
MATCH (p:Paper {id: 'paper_001'})
RETURN p.view_count, p.tags

// GCounter returns total count
// ORSet returns list of visible elements
// LWWMap returns map of non-tombstoned entries

Updating CRDT Properties

CRDT updates use special syntax to ensure conflict-free merging:

// Increment a GCounter
MATCH (p:Paper {id: 'paper_001'})
SET p.view_count = crdt.increment(p.view_count, 1)

// Add to an ORSet
MATCH (p:Paper {id: 'paper_001'})
SET p.tags = crdt.add(p.tags, 'machine-learning')

// Remove from an ORSet
MATCH (p:Paper {id: 'paper_001'})
SET p.tags = crdt.remove(p.tags, 'deprecated-tag')

// Update LWWMap
MATCH (p:Paper {id: 'paper_001'})
SET p.metadata = crdt.put(p.metadata, 'reviewed', true)

CRDT Functions

Function CRDT Types Description
crdt.increment(counter, n) GCounter Increment by n
crdt.add(set, elem) GSet, ORSet Add element
crdt.remove(set, elem) ORSet Remove element
crdt.set(register, value) LWWRegister Set value
crdt.put(map, key, value) LWWMap Put key-value
crdt.delete(map, key) LWWMap Delete key
crdt.insert(rga, index, elem) Rga Insert at position
crdt.deleteAt(rga, index) Rga Delete at position

Distributed Sync

CRDT properties enable conflict-free synchronization across distributed nodes:

┌─────────────┐         ┌─────────────┐
│   Node A    │◄───────►│   Node B    │
│             │         │             │
│ increment   │         │ increment   │
│ view_count  │         │ view_count  │
│    +5       │         │    +3       │
└──────┬──────┘         └──────┬──────┘
       │                       │
       └───────────┬───────────┘
            ┌─────────────┐
            │   Merged    │
            │ view_count  │
            │     = 8     │
            └─────────────┘

For detailed CRDT semantics and merge behavior, see CRDT Types.


Cypher Feature Status

Feature Status
MATCH (basic patterns) Stable
WHERE (comparisons, boolean) Stable
RETURN, ORDER BY, LIMIT, SKIP Stable
Aggregations (COUNT, SUM, AVG, MIN, MAX, COLLECT) Stable
Window Functions (OVER clause) Stable
Scalar Functions (40+ functions) Stable
CREATE (nodes and relationships) Stable
WITH clause Stable
UNWIND Stable
CALL procedures Stable
Index management Stable
JSON Full-Text Search (CONTAINS) Stable
Variable-length paths (*1..3) Stable
MERGE Stable
SET / REMOVE Stable
DELETE / DETACH DELETE Stable
UNION / UNION ALL Stable
WITH RECURSIVE (CTEs) Stable
EXPLAIN (with index usage) Stable
PROFILE (runtime statistics) Stable
Session Variables ($session.*) Stable
Temporal Queries (uni.validAt, VALID_AT) Stable
Schema DDL (CREATE/ALTER/DROP LABEL) Stable
Schema DDL Procedures (db.createLabel, etc.) Stable
Constraints (UNIQUE, EXISTS, CHECK) Stable
Composite Key Constraints Stable
Graph Algorithms (36 algorithms) Stable
CRDT Properties Stable
Database Management (BACKUP, VACUUM, CHECKPOINT) Stable
Snapshots (create, list, restore) Stable
Schema Introspection (db.labels, db.indexes, etc.) Stable
Inverted Index (ANY IN pattern) Stable
OPTIONAL MATCH Planned
Subqueries Planned

Next Steps