Live Query Promises
Live query promises provide interfaces for subscribing to real-time updates from SurrealDB. There are two variants: ManagedLivePromise for new subscriptions and UnmanagedLivePromise for existing ones.
Returned by: SurrealQueryable.live(), SurrealQueryable.liveOf()
Source: query/live.ts
ManagedLivePromise<T>
A managed live query subscription that the SDK automatically creates and manages.
Returned by: SurrealQueryable.live()
Configuration Methods
.diff()
Configure the subscription to return only patches (diffs) instead of full records on updates.
Method Syntax
livePromise.diff()
Returns: ManagedLivePromise<T> - Chainable promise
Example:
const subscription = await db.live(new Table('users')).diff();
for await (const update of subscription) {
console.log('Diff:', update.diff);
}
.fields()
Select only specific fields in the live updates.
Method Syntax
livePromise.fields(...fields)
Parameters:
| Parameter | Type | Description |
|---|
fields required | Field<T>[] | Field names to include in updates. |
Returns: ManagedLivePromise<T>
Example:
const subscription = await db.live(new Table('users'))
.fields('name', 'email', 'status');
for await (const update of subscription) {
console.log(update.result);
}
.value()
Return only the value of a specific field in updates.
Method Syntax
livePromise.value(field)
Parameters:
| Parameter | Type | Description |
|---|
field required | Field<T> | Field name to extract. |
Returns: ManagedLivePromise<T>
Example:
const subscription = await db.live(new Table('users'))
.value('name');
for await (const update of subscription) {
console.log('Name changed:', update.result);
}
.where()
Filter live updates to only receive records matching the condition.
Method Syntax
livePromise.where(condition)
Parameters:
| Parameter | Type | Description |
|---|
condition required | ExprLike | Condition expression to filter updates (string or Expression object). |
Returns: ManagedLivePromise<T>
Example:
const subscription = await db.live(new Table('users'))
.where('age >= 18');
for await (const update of subscription) {
console.log(update.action, update.result);
}
.fetch()
Fetch related records in live updates.
Method Syntax
livePromise.fetch(...fields)
Parameters:
| Parameter | Type | Description |
|---|
fields required | Field<T>[] | Related fields to fetch. |
Returns: ManagedLivePromise<T>
Example:
const subscription = await db.live(new Table('posts'))
.fetch('author', 'comments');
for await (const update of subscription) {
console.log('Post by:', update.result.author.name);
}
Live Subscription Methods
Once awaited, a ManagedLivePromise returns a LiveSubscription object:
Iteration
for await (const update of subscription) {
console.log(update.action);
console.log(update.result);
}
.kill()
Kill the live query subscription.
await subscription.kill();
UnmanagedLivePromise
An unmanaged subscription to an existing live query by its UUID.
Returned by: SurrealQueryable.liveOf()
Usage
const liveQueryId: Uuid = ;
const subscription = await db.liveOf(liveQueryId);
for await (const update of subscription) {
console.log(update);
}
Complete Examples
Basic Live Query
import { Surreal, Table } from 'surrealdb';
const db = new Surreal();
await db.connect('ws://localhost:8000');
const subscription = await db.live(new Table('users'));
for await (const update of subscription) {
console.log(`${update.action}:`, update.result);
}
await subscription.kill();
Filtered Live Query
const subscription = await db.live(new Table('users'))
.where('status = "active"');
for await (const update of subscription) {
if (update.action === 'CREATE') {
console.log('New active user:', update.result);
} else if (update.action === 'UPDATE') {
console.log('Active user updated:', update.result);
} else if (update.action === 'DELETE') {
console.log('Active user deleted:', update.result);
}
}
Live Query with Specific Fields
const subscription = await db.live(new Table('users'))
.fields('name', 'email', 'status')
.where('role = "admin"');
for await (const update of subscription) {
console.log('Admin update:', update.result);
}
await subscription.kill();
Diff-Based Updates
const subscription = await db.live(new Table('users')).diff();
for await (const update of subscription) {
if (update.action === 'UPDATE') {
console.log('Changed fields:', update.diff);
}
}
Live Query with Relations
const subscription = await db.live(new Table('posts'))
.fetch('author', 'comments')
.where('published = true');
for await (const update of subscription) {
console.log('Post by:', update.result.author.name);
console.log('Comments:', update.result.comments.length);
}
Real-time Dashboard
async function monitorUsers(callback: (stats: any) => void) {
const subscription = await db.live(new Table('users'));
const stats = {
created: 0,
updated: 0,
deleted: 0
};
for await (const update of subscription) {
if (update.action === 'CREATE') stats.created++;
else if (update.action === 'UPDATE') stats.updated++;
else if (update.action === 'DELETE') stats.deleted++;
callback(stats);
}
}
monitorUsers((stats) => {
console.log('User stats:', stats);
});
Watch Specific Record
const subscription = await db.live(new RecordId('users', 'john'));
for await (const update of subscription) {
if (update.action === 'UPDATE') {
console.log('John was updated:', update.result);
} else if (update.action === 'DELETE') {
console.log('John was deleted');
break;
}
}
Auto-reconnect Live Query
let subscription: LiveSubscription | null = null;
async function setupLiveQuery() {
subscription = await db.live(new Table('users'))
.where('active = true');
for await (const update of subscription) {
console.log('Update:', update);
}
}
db.subscribe('reconnecting', () => {
console.log('Connection lost, live query will be restored...');
});
db.subscribe('connected', async () => {
console.log('Reconnected, live queries restored automatically');
});
await setupLiveQuery();
Cleanup Pattern
const subscriptions: LiveSubscription[] = [];
subscriptions.push(await db.live(new Table('users')));
subscriptions.push(await db.live(new Table('posts')));
subscriptions.push(await db.live(new Table('comments')));
async function cleanup() {
await Promise.all(subscriptions.map(sub => sub.kill()));
console.log('All subscriptions cleaned up');
}
await cleanup();
Error Handling
try {
const subscription = await db.live(new Table('users'));
try {
for await (const update of subscription) {
await processUpdate(update);
}
} catch (error) {
console.error('Error processing update:', error);
} finally {
await subscription.kill();
}
} catch (error) {
if (error instanceof LiveSubscriptionError) {
console.error('Failed to create subscription:', error);
}
}
Update Message Structure
Each update message conforms to the LiveMessage<T> interface with action, result, and optional diff properties.
Processing Updates
for await (const update of subscription) {
switch (update.action) {
case 'CREATE':
await handleCreate(update.result);
break;
case 'UPDATE':
await handleUpdate(update.result, update.diff);
break;
case 'DELETE':
await handleDelete(update.result);
break;
}
}
See Also