SurrealDB
SurrealDB Docs Logo

Enter a search query

Navigation

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); // Only changed fields }

.fields()

Select only specific fields in the live updates.

Method Syntax
livePromise.fields(...fields)

Parameters:

ParameterTypeDescription
fields requiredField<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 Syntax
livePromise.value(field)

Parameters:

ParameterTypeDescription
field requiredField<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 Syntax
livePromise.where(condition)

Parameters:

ParameterTypeDescription
condition requiredExprLikeCondition 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 Syntax
livePromise.fetch(...fields)

Parameters:

ParameterTypeDescription
fields requiredField<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); }

Live Subscription Methods

Once awaited, a ManagedLivePromise returns a LiveSubscription object:

Iteration

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();

UnmanagedLivePromise

An unmanaged subscription to an existing live query by its UUID.

Returned by: SurrealQueryable.liveOf()

Usage

const liveQueryId: Uuid = /* from somewhere */; 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'); // 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();

Filtered Live Query

// 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); } }

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) { // Only receives name, email, status fields console.log('Admin update:', update.result); } await subscription.kill();

Diff-Based Updates

// 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 } }

Live Query with Relations

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); }

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

// 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; } }

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); } } // 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();

Cleanup Pattern

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();

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