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()
.diff()Configure the subscription to return only patches (diffs) instead of full records on updates.
Method SyntaxlivePromise.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); // Only changed fields }
.fields()Select only specific fields in the live updates.
Method SyntaxlivePromise.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) { // Only includes specified fields console.log(update.result); // { name, email, status } }
.value()Return only the value of a specific field in updates.
Method SyntaxlivePromise.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); // Just the name string }
.where()Filter live updates to only receive records matching the condition.
Method SyntaxlivePromise.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) { // Only receives updates for users with age >= 18 console.log(update.action, update.result); }
.fetch()Fetch related records in live updates.
Method SyntaxlivePromise.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) { // author and comments are fully populated console.log('Post by:', update.result.author.name); }
Once awaited, a ManagedLivePromise returns a LiveSubscription object:
for await (const update of subscription) { console.log(update.action); // 'CREATE' | 'UPDATE' | 'DELETE' console.log(update.result); // The record data }
.kill()Kill the live query subscription.
await subscription.kill();
UnmanagedLivePromiseAn unmanaged subscription to an existing live query by its UUID.
Returned by: SurrealQueryable.liveOf()
const liveQueryId: Uuid = /* from somewhere */; const subscription = await db.liveOf(liveQueryId); for await (const update of subscription) { console.log(update); }
import { Surreal, Table } from 'surrealdb'; const db = new Surreal(); await db.connect('ws://localhost:8000'); // Subscribe to all user changes const subscription = await db.live(new Table('users')); for await (const update of subscription) { console.log(`${update.action}:`, update.result); } // Clean up when done await subscription.kill();
// Only receive updates for active users 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); } }
const subscription = await db.live(new Table('users')) .fields('name', 'email', 'status') .where('role = "admin"'); for await (const update of subscription) { // Only receives name, email, status fields console.log('Admin update:', update.result); } await subscription.kill();
// Get only changes, not full records 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); // { email: 'new@example.com' } instead of full record } }
const subscription = await db.live(new Table('posts')) .fetch('author', 'comments') .where('published = true'); for await (const update of subscription) { // author is fully populated console.log('Post by:', update.result.author.name); console.log('Comments:', update.result.comments.length); }
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); });
// Subscribe to changes on a 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; } }
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); } } // Handle reconnection 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();
const subscriptions: LiveSubscription[] = []; // Create multiple subscriptions subscriptions.push(await db.live(new Table('users'))); subscriptions.push(await db.live(new Table('posts'))); subscriptions.push(await db.live(new Table('comments'))); // Process updates // ... // Cleanup all subscriptions async function cleanup() { await Promise.all(subscriptions.map(sub => sub.kill())); console.log('All subscriptions cleaned up'); } // Call on app shutdown await cleanup();
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); } }
Each update message conforms to the LiveMessage<T> interface with action, result, and optional diff properties.
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; } }