Edge Properties
Edge Properties
Level 5 — Relational Data & Graph Operations The metadata properties stored directly on graph relationship records (edges) in SurrealDB, and the query paths used to extract these attributes instead of traversing past them to the target nodes.
1. Prerequisites
RELATEStatement — The command creating the edges.object— Nested metadata structures.
2. Term Category
Schema & Modeling (graph edge record properties and metadata): - Database Structure / Paradigm
3. Explanation
(1) Design Motivation — "Why did we design this?"
Relationships in the real world have attributes:
- A user doesn't just "know" another user; they met at a specific time, and have a level of closeness (closeness score).
- A customer doesn't just "buy" a product; they buy a specific quantity, at a specific price, on a specific date.
In SQL, you store these attributes inside columns of many-to-many junction tables.
In basic graph databases, accessing edge attributes requires complex syntax extensions.
We designed Edge Properties in SurrealDB to treat relationships as first-class documents.
Because graph edges are records stored in relation tables, they can hold any standard data type (integers, strings, arrays, nested objects).
You store relationship metadata directly on the edge.
When querying, you can select these properties by targeting the edge path (e.g. ->bought.quantity) rather than jumping past the edge to the target node.
(2) Querying Edge Properties
Understanding the traversal path is critical to extract edge properties:
- Traversing to Target Node:
->bought->product(jumps past the edge, returning the product record details). - Traversing to Edge Properties:
->bought.priceor->bought(stops at the edge, returning the properties stored on theboughtrelationship record).
(3) Reality Metaphor (Highway Toll Tickets)
Imagine driving between cities:
- Nodes (Cities): New York and Boston.
- Edge (Highway Road): The physical highway connecting them.
- Edge Properties: The Toll Booth Ticket handed to you when you enter the highway.
- The ticket stores: the entrance time, your vehicle weight, and the toll fee.
- This data does not belong to New York or Boston; it is printed on the highway ticket itself.
(4) Code Examples
Writing and Reading Edge Properties in SurrealQL
Let's model a customer purchase graph:
-- 1. Create a relationship with edge properties (quantity and price)
RELATE user:john -> bought -> product:laptop
SET quantity = 2,
unit_price = 1200.00dec,
purchased_at = time::now();
-- 2. Query target details (jumps PAST edge properties to get product title)
SELECT ->bought->product.title AS product_name FROM user:john;
-- Returns: [ { "product_name": ["Laptop Pro"] } ]
-- 3. Query edge properties (stops AT the edge to get unit_price)
SELECT ->bought.unit_price AS prices FROM user:john;
-- Returns: [ { "prices": [1200.00dec] } ]
-- 4. Retrieve both the edge properties AND the target node details together
-- (By selecting the edge records, which contain 'out' pointers)
SELECT ->bought AS purchases FROM user:john;
-- Returns:
// [
// {
// "purchases": [
// {
// "id": bought:a9f8g...,
// "in": user:john,
// "out": product:laptop, // Target link
// "quantity": 2,
// "unit_price": 1200.00dec,
// "purchased_at": d"2026-07-21T15:00:00Z"
// }
// ]
// }
// ]
4. Common Mistakes & Pitfalls
Mistake 1: Attempting to query edge properties by chaining through the target node, resulting in 'NONE' evaluations
The mistake: Writing the query SELECT ->bought->product.quantity FROM user:john; expecting to retrieve the number of items purchased.
Why it's wrong: The ->product segment tells SurrealDB to jump to the product table.
Because quantity is stored on the edge (bought table) and not on the product schema (the product catalog doesn't track individual checkout quantities), the database returns NONE.
Fix: Do not include the target table in your selection path when querying edge properties. Stop at the edge name:
-- BAD (Looks on product table)
SELECT ->bought->product.quantity FROM user:john;
-- GOOD (Looks on bought edge table)
SELECT ->bought.quantity FROM user:john;
Mistake 2: Storing Relationship Properties in Node Records instead of Graph Edge Records
The mistake: Storing relationship_created_at or role fields on the user or group node records.
Why it's wrong: Properties belonging to the connection itself (like rating, permission_level, created_at) belong on the edge record created by RELATE.
Incorrect:
CREATE user:alice SET membership_role = "admin"; // ❌ Store on node instead of edge!
Fix:
RELATE user:alice->member_of->group:tech SET role = "admin", created_at = time::now();
Mistake 3: Querying Edge Properties Without Including Edge Table Names in Arrow Paths
The mistake: Writing SELECT ->member_of.role FROM user:alice; omitting the target node table.
Why it's wrong: To project edge properties, reference the edge table in the arrow path ->member_of[WHERE role = 'admin']->group or query the edge table directly.
Incorrect:
SELECT ->member_of.role FROM user:alice; // ❌ Incomplete arrow projection!
Fix:
SELECT ->member_of[WHERE role = "admin"]->group AS admin_groups FROM user:alice;
5. Practice Exercises
Exercise 1: Adding Metadata Properties to Relation Edges
Scenario:
An e-commerce system relates a user to a product via a purchased relation edge, storing metadata fields price_paid (decimal) and purchased_at (datetime).
Requirements:
- Execute
RELATE user:alice -> purchased -> product:p1setting edge metadata fields. - Select the relation edge record to verify stored properties.
Answer
Implementation
CREATE user:alice SET name = "Alice";
CREATE product:p1 SET name = "Laptop";
-- Create relation edge with metadata properties
RELATE user:alice->purchased->product:p1 SET
price_paid = 1199.99dec,
purchased_at = time::now(),
rating = 5;
SELECT * FROM purchased;
Technical Explanation
- SurrealDB relation edges are first-class record documents capable of storing arbitrary properties.
- Stores
in(source pointer),out(target pointer), and custom metadata fields (price_paid). - Eliminates separate SQL junction tables with extra payload columns.
Exercise 2: Filtering Queries by Edge Properties
Scenario:
Query all products purchased by user:alice where the edge metadata property rating is .
Requirements:
- Write a
SELECTquery traversing->purchased[WHERE rating >= 4]->product.
Answer
Implementation
-- Filter traversal by edge record metadata property
SELECT ->purchased[WHERE rating >= 4]->product.name AS highly_rated_purchases
FROM user:alice;
Technical Explanation
[WHERE rating >= 4]filters the relation edge records (purchased) during arrow traversal.- Only follows edge paths that satisfy edge property constraints.
- Combines graph topology navigation with rich metadata filtering.
Exercise 3: Updating Properties on Existing Relation Edges
Scenario:
Update the rating property on an existing purchased relation edge between user:alice and product:p1.
Requirements:
- Update relation edge
purchasedsettingrating = 5.
Answer
Implementation
-- Update edge property
UPDATE purchased SET rating = 5 WHERE in = user:alice AND out = product:p1;
Technical Explanation
- Relation edges can be updated like standard database tables using
UPDATE. - Matching on
inandouttargets specific edge instances directly. - Mutates edge properties without breaking graph vertex connections.
6. Related Terms
RELATEStatement — The command creating the edges.- Graph Traversal Filtering (
WHEREon edges) — Filtering using edge properties.
7. Key Takeaways
- Edges act as first-class documents and can store any data type properties.
- Relational equivalent to columns in SQL many-to-many junction tables.
- Querying
->edge->targetbypasses edge properties to fetch target fields. - Querying
->edge.propertyextracts metadata stored on the relationship edge. - Do not chain the target table name when selecting edge properties.
- Storing properties on edges is ideal for timestamps, ratings, and quantities.
- Retrieve the complete edge record (including
outlinks) by selecting->edge.