The RelatePromise class provides a chainable interface for configuring RELATE operations to create graph relationships (edges) between records. It extends Promise, allowing you to await it directly or chain configuration methods.
Returned by: SurrealQueryable.relate()
Source: query/relate.ts
Type parameters
T- The result type (edge record type)J- Boolean indicating if result is JSON (default:false)
Configuration methods
.unique()
Enforce a unique relationship constraint (only one edge between the same nodes).
relatePromise.unique()Returns
`RelatePromise` - Chainable promise
Example
// Only allow one 'likes' edge between user and post
const edge = await db.relate(
new RecordId('users', 'john'),
new Table('likes'),
new RecordId('posts', '1')
).unique();
// If edge already exists, this won't create a duplicate .output()
Specify what to return from the operation.
relatePromise.output(fields)Parameters
Parameter | Type | Description |
|---|---|---|
fields | Output | "NONE", "AFTER", or specific field list. |
Returns
`RelatePromise` - Chainable promise
Example
const edge = await db.relate(
new RecordId('users', 'john'),
new Table('follows'),
new RecordId('users', 'jane')
).output('id', 'in', 'out', 'created_at'); .timeout()
Set a timeout for the operation.
relatePromise.timeout(duration)Parameters
Parameter | Type | Description |
|---|---|---|
duration | Duration | Maximum time to wait. |
Returns
`RelatePromise` - Chainable promise
.version()
Create the relationship at a specific version.
relatePromise.version(timestamp)Parameters
Parameter | Type | Description |
|---|---|---|
timestamp | DateTime | The version timestamp. |
Returns
`RelatePromise` - Chainable promise
.retry()
Retry the operation with exponential backoff if it fails due to a write conflict. Off by default; passing an options object (or calling with no arguments) opts the operation in.
This overrides the connection-wide default set via the retry option on ConnectOptions.
relatePromise.retry(options?)Parameters
Parameter | Type | Description |
|---|---|---|
options | Partial RetryOptions | Retry configuration. If omitted, retry is enabled with the default configuration. |
Returns
`RelatePromise` - Chainable promise
Example
await db.relate(alice, 'follows', bob).retry(); .json()
Return result as JSON string.
relatePromise.json()Returns
`RelatePromise` - Promise returning JSON string
.compile()
Compile the query into a BoundQuery.
relatePromise.compile()Returns
`BoundQuery` - The compiled query
.stream()
Stream results as relationships are created.
relatePromise.stream()Returns
AsyncIterableIterator - Async iterator
Complete examples
Basic relationship
import { Surreal, RecordId, Table, DateTime } from 'surrealdb';
const db = new Surreal();
await db.connect('ws://localhost:8000');
// Create a single relationship
const edge = await db.relate(
new RecordId('users', 'john'),
new Table('likes'),
new RecordId('posts', '1'),
{ created_at: DateTime.now() }
);
console.log('Edge created:', edge.id);
console.log('From:', edge.in); // users:john
console.log('To:', edge.out); // posts:1Multiple relationships
// Create multiple edges at once
const edges = await db.relate(
[new RecordId('users', 'john'), new RecordId('users', 'jane')],
new Table('follows'),
[new RecordId('users', 'alice'), new RecordId('users', 'bob')]
);
// Creates 4 edges:
// john->follows->alice
// john->follows->bob
// jane->follows->alice
// jane->follows->bobUnique relationships
// Prevent duplicate 'likes'
const edge = await db.relate(
new RecordId('users', 'john'),
new Table('likes'),
new RecordId('posts', '1'),
{ timestamp: DateTime.now() }
).unique();
// Second call won't create duplicate
const duplicate = await db.relate(
new RecordId('users', 'john'),
new Table('likes'),
new RecordId('posts', '1')
).unique();
// Returns existing edgeRelationship with data
const friendship = await db.relate(
new RecordId('users', 'john'),
new Table('friends'),
new RecordId('users', 'jane'),
{
since: DateTime.parse('2024-01-15'),
strength: 0.8,
mutual: true,
tags: ['colleague', 'neighbor']
}
);Specific edge ID
// Use specific ID for the edge
const edge = await db.relate(
new RecordId('users', 'john'),
new RecordId('likes', 'specific-edge-id'),
new RecordId('posts', '1'),
{ strength: 10 }
);Fan-out relationships
// One user follows many
const edges = await db.relate(
new RecordId('users', 'john'),
new Table('follows'),
[
new RecordId('users', 'alice'),
new RecordId('users', 'bob'),
new RecordId('users', 'carol')
]
);
console.log(`Created ${edges.length} follow edges`);Streaming bulk relationships
const users = await db.select(new Table('users'));
const popularPost = new RecordId('posts', 'viral-post');
const edges = db.relate(
users.map(u => u.id),
new Table('viewed'),
popularPost,
{ viewed_at: DateTime.now() }
);
for await (const edge of edges.stream()) {
console.log(`Created view edge: ${edge.id}`);
}Bidirectional relationships
// Create friendship in both directions
await db.relate(
new RecordId('users', 'john'),
new Table('friends'),
new RecordId('users', 'jane')
);
await db.relate(
new RecordId('users', 'jane'),
new Table('friends'),
new RecordId('users', 'john')
);Relationship metadata
const edge = await db.relate(
new RecordId('users', 'john'),
new Table('rated'),
new RecordId('movies', 'inception'),
{
rating: 5,
review: 'Amazing movie!',
watched_at: DateTime.parse('2024-01-15'),
platform: 'Netflix'
}
);Temporal relationships
// Track when relationship was created
const edge = await db.relate(
new RecordId('users', 'john'),
new Table('employed_at'),
new RecordId('companies', 'acme'),
{
started_at: DateTime.parse('2024-01-01'),
position: 'Developer',
department: 'Engineering'
}
);Weighted graph
// Create weighted edges for graph algorithms
const edge = await db.relate(
new RecordId('cities', 'new-york'),
new Table('connected_to'),
new RecordId('cities', 'boston'),
{
distance: 215, // miles
travel_time: Duration.parse('4h'),
cost: 50
}
);Delete and recreate pattern
// Remove existing relationship and create new one
const userId = new RecordId('users', 'john');
const postId = new RecordId('posts', '1');
// Delete existing edge
await db.query(
surql`DELETE FROM likes WHERE in = ${userId} AND out = ${postId}`
).collect();
// Create new edge with updated data
const edge = await db.relate(
userId,
new Table('likes'),
postId,
{ created_at: DateTime.now() }
);Graph traversal example
// Create relationships
await db.relate(
new RecordId('users', 'john'),
new Table('follows'),
new RecordId('users', 'jane')
);
// Query traversal
const followers = await db.query(
surql`SELECT <-follows<-users.* AS followers FROM users:jane`
).collect();
console.log('Jane has followers:', followers);Best practices
1. Use unique for one-to-one
// Good: Prevent duplicate likes
await db.relate(from, new Table('likes'), to).unique();
// Avoid: Allowing duplicates
await db.relate(from, new Table('likes'), to);
// May create multiple edges2. Include metadata
// Good: Track when relationship was created
await db.relate(from, edge, to, {
created_at: DateTime.now(),
source: 'web-app'
});
// Basic: No metadata
await db.relate(from, edge, to);3. Use specific edge IDs for updates
// Good: use a specific ID so you can update the edge later
const edgeId = new RecordId('likes', [from.toString(), to.toString()]);
await db.relate(from, edgeId, to, metadata);
// Later: update by record ID
await db.update(edgeId).merge({ updated_at: DateTime.now() });As of SurrealDB 3.1.5, when the edge ID already exists, INSERT RELATION returns an error unless you use ON DUPLICATE KEY UPDATE. See Explicit edge record IDs for more details.
See also
SurrealQueryable.relate() - Method that returns RelatePromise
Graph relationships - SurrealQL RELATE documentation
RecordId - Record identifier type
Query overview - All query builder classes