Skip to content

Graph Database: Cypher Query Language

Graph Database: Cypher Query Language

Part of: Graph Database User Guide


HeliosDB supports a Cypher-like query language for declarative graph queries. This section covers all query clauses with examples.

MATCH Patterns

The MATCH clause finds patterns in the graph.

Example 1: Simple Node Match

// Find all Person nodes
let query = CypherQuery {
match_clause: Some(MatchClause {
patterns: vec![Pattern {
nodes: vec![NodePattern {
variable: "p".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
}],
relationships: vec![],
}],
}),
return_clause: ReturnClause {
items: vec![ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "name".to_string(),
},
alias: Some("name".to_string()),
}],
distinct: false,
},
where_clause: None,
order_by: None,
limit: None,
skip: None,
};

Example 2: Match with Relationship

// Find who follows whom
let query = CypherQuery {
match_clause: Some(MatchClause {
patterns: vec![Pattern {
nodes: vec![
NodePattern {
variable: "follower".to_string(),
labels: vec!["User".to_string()],
properties: HashMap::new(),
},
NodePattern {
variable: "followed".to_string(),
labels: vec!["User".to_string()],
properties: HashMap::new(),
},
],
relationships: vec![RelationshipPattern {
variable: Some("rel".to_string()),
types: vec!["FOLLOWS".to_string()],
direction: Direction::Outgoing,
properties: HashMap::new(),
length: PathLength::Fixed(1),
}],
}],
}),
return_clause: ReturnClause {
items: vec![
ReturnItem {
expression: Expression::Property {
variable: "follower".to_string(),
property: "username".to_string(),
},
alias: Some("follower".to_string()),
},
ReturnItem {
expression: Expression::Property {
variable: "followed".to_string(),
property: "username".to_string(),
},
alias: Some("followed".to_string()),
},
],
distinct: false,
},
where_clause: None,
order_by: None,
limit: None,
skip: None,
};

WHERE Filtering

Filter results based on conditions.

Example 3: Filter by Property

use heliosdb_graph::cypher::{WhereClause, Condition, ComparisonOp};
let query = CypherQuery {
match_clause: Some(MatchClause {
patterns: vec![Pattern {
nodes: vec![NodePattern {
variable: "p".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
}],
relationships: vec![],
}],
}),
where_clause: Some(WhereClause {
condition: Condition::Comparison {
left: Expression::Property {
variable: "p".to_string(),
property: "age".to_string(),
},
op: ComparisonOp::Gt,
right: Expression::Literal(json!(25)),
},
}),
return_clause: ReturnClause {
items: vec![ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "name".to_string(),
},
alias: Some("name".to_string()),
}],
distinct: false,
},
order_by: None,
limit: None,
skip: None,
};

Example 4: Complex Conditions (AND/OR)

let query = CypherQuery {
match_clause: Some(MatchClause {
patterns: vec![Pattern {
nodes: vec![NodePattern {
variable: "p".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
}],
relationships: vec![],
}],
}),
where_clause: Some(WhereClause {
condition: Condition::And(
Box::new(Condition::Comparison {
left: Expression::Property {
variable: "p".to_string(),
property: "age".to_string(),
},
op: ComparisonOp::Ge,
right: Expression::Literal(json!(25)),
}),
Box::new(Condition::Comparison {
left: Expression::Property {
variable: "p".to_string(),
property: "city".to_string(),
},
op: ComparisonOp::Eq,
right: Expression::Literal(json!("San Francisco")),
}),
),
}),
return_clause: ReturnClause {
items: vec![ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "name".to_string(),
},
alias: Some("name".to_string()),
}],
distinct: false,
},
order_by: None,
limit: None,
skip: None,
};
// Equivalent Cypher:
// MATCH (p:Person)
// WHERE p.age >= 25 AND p.city = 'San Francisco'
// RETURN p.name

RETURN Projections

Specify what data to return.

Example 5: Return Multiple Properties

let return_clause = ReturnClause {
items: vec![
ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "name".to_string(),
},
alias: Some("person_name".to_string()),
},
ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "age".to_string(),
},
alias: Some("person_age".to_string()),
},
ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "email".to_string(),
},
alias: Some("email".to_string()),
},
],
distinct: false,
};

Example 6: DISTINCT Results

let return_clause = ReturnClause {
items: vec![ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "city".to_string(),
},
alias: Some("city".to_string()),
}],
distinct: true, // Remove duplicates
};

CREATE Nodes/Edges

Add new data to the graph.

Example 7: Create Node

// Create a new person
let new_person = Node {
id: 0,
label: "Person".to_string(),
properties: HashMap::from([
("name".to_string(), json!("Diana")),
("age".to_string(), json!(30)),
("city".to_string(), json!("Seattle")),
]),
};
let diana_id = storage.add_vertex(new_person).await?;
println!("Created node with ID: {}", diana_id);

Example 8: Create Relationship

// Create friendship between Alice and Diana
let friendship = Edge {
id: 0,
source: alice_id,
target: diana_id,
label: "FRIEND_OF".to_string(),
weight: 1.0,
properties: HashMap::from([
("since".to_string(), json!("2024-11-01")),
("strength".to_string(), json!(0.8)),
]),
};
let edge_id = storage.add_edge(friendship).await?;
println!("Created edge with ID: {}", edge_id);

UPDATE Properties

Modify existing nodes or edges.

Example 9: Update Node Properties

// Get the node
if let Some(mut node) = storage.get_vertex(alice_id).await? {
// Update properties
node.properties.insert("age".to_string(), json!(29));
node.properties.insert("last_updated".to_string(), json!("2025-11-02"));
// Save (this would require update_vertex method)
// storage.update_vertex(node).await?;
}

DELETE Nodes/Edges

Remove data from the graph.

Example 10: Delete Edge

// Delete a specific edge
// storage.delete_edge(edge_id).await?;

Example 11: Delete Node

// Delete a node (and optionally its edges)
// storage.delete_vertex(alice_id, true).await?; // true = cascade delete edges

ORDER BY, LIMIT, SKIP

Control result ordering and pagination.

Example 12: Order and Limit Results

use heliosdb_graph::cypher::{OrderByClause, OrderByItem};
let query = CypherQuery {
match_clause: Some(MatchClause {
patterns: vec![Pattern {
nodes: vec![NodePattern {
variable: "p".to_string(),
labels: vec!["Person".to_string()],
properties: HashMap::new(),
}],
relationships: vec![],
}],
}),
where_clause: None,
return_clause: ReturnClause {
items: vec![
ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "name".to_string(),
},
alias: Some("name".to_string()),
},
ReturnItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "age".to_string(),
},
alias: Some("age".to_string()),
},
],
distinct: false,
},
order_by: Some(OrderByClause {
items: vec![OrderByItem {
expression: Expression::Property {
variable: "p".to_string(),
property: "age".to_string(),
},
ascending: false, // Descending order
}],
}),
limit: Some(10), // Top 10 results
skip: Some(0),
};
// Equivalent Cypher:
// MATCH (p:Person)
// RETURN p.name AS name, p.age AS age
// ORDER BY p.age DESC
// LIMIT 10

Example 13: Pagination

// Page 1 (results 1-10)
let page1_query = CypherQuery {
// ... match and return clauses ...
order_by: Some(OrderByClause { /* ... */ }),
limit: Some(10),
skip: Some(0),
// ...
};
// Page 2 (results 11-20)
let page2_query = CypherQuery {
// ... match and return clauses ...
order_by: Some(OrderByClause { /* ... */ }),
limit: Some(10),
skip: Some(10),
// ...
};
// Page 3 (results 21-30)
let page3_query = CypherQuery {
// ... match and return clauses ...
order_by: Some(OrderByClause { /* ... */ }),
limit: Some(10),
skip: Some(20),
// ...
};


Version: 6.5 Last Updated: November 17, 2025