The UpsertPromise class provides a chainable interface for configuring UPSERT operations (insert if not exists, replace if exists). It extends Promise, allowing you to await it directly or chain configuration methods.
UPSERT replaces the entire record if it exists. Use update().merge() for partial updates.
Returned by: SurrealQueryable.upsert()
Source: query/upsert.ts
Type parameters
T- The result typeI- The input type for record dataJ- Boolean indicating if result is JSON (default:false)
Configuration methods
.content()
Set the complete content for the record (insert or replace).
upsertPromise.content(data)Parameters
Parameter | Type | Description |
|---|---|---|
data | Values<I> | Complete record data (excluding id field). |
Returns
`UpsertPromise` - Chainable promise
Example
const user = await db.upsert(new RecordId('users', 'john'))
.content({
name: 'John Doe',
email: 'john@example.com',
age: 30
});
// Inserts if not exists, replaces entirely if exists .merge()
Merge data into the record (insert if not exists, merge if exists).
upsertPromise.merge(data)Parameters
Parameter | Type | Description |
|---|---|---|
data | Values<I> | Partial data to merge. |
Returns
`UpsertPromise` - Chainable promise
Example
const user = await db.upsert(new RecordId('users', 'john'))
.merge({
name: 'John Doe',
last_login: DateTime.now()
});
// If exists: merges fields; if not: creates with these fields .replace()
Replace specific fields.
upsertPromise.replace(data)Parameters
Parameter | Type | Description |
|---|---|---|
data | Values<I> | Fields to replace. |
Returns
`UpsertPromise` - Chainable promise
.patch()
Apply JSON Patch operations.
upsertPromise.patch(operations)Parameters
Parameter | Type | Description |
|---|---|---|
operations | Values<I> | JSON Patch operations. |
Returns
`UpsertPromise` - Chainable promise
.where()
Add a WHERE clause for conditional upsert.
upsertPromise.where(expr)Parameters
Parameter | Type | Description |
|---|---|---|
expr | ExprLike | The condition expression (string or Expression object). |
Returns
`UpsertPromise` - Chainable promise
.output()
Specify what to return.
upsertPromise.output(fields)Parameters
Parameter | Type | Description |
|---|---|---|
fields | Output | "NONE", "BEFORE", "AFTER", "DIFF", or field list. |
Returns
`UpsertPromise` - Chainable promise
.timeout()
Set operation timeout.
upsertPromise.timeout(duration)Returns
`UpsertPromise` - 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.
upsertPromise.retry(options?)Parameters
Parameter | Type | Description |
|---|---|---|
options | Partial RetryOptions | Retry configuration. If omitted, retry is enabled with the default configuration. |
Returns
`UpsertPromise` - Chainable promise
Example
await db.upsert(new RecordId('users', 'john'))
.merge({ visits: 1 })
.retry(); .json()
Return result as JSON string.
upsertPromise.json()Returns
`UpsertPromise` - Promise returning JSON string
.compile()
Compile the query into a BoundQuery without executing it.
upsertPromise.compile()Returns
`BoundQuery` - The compiled query
Example
const query = db.upsert(new RecordId('users', 'john'))
.content(userData)
.compile(); .stream()
Stream results as they arrive.
upsertPromise.stream()Returns
AsyncIterableIterator - Async iterator
Complete examples
Basic upsert
import { Surreal, RecordId } from 'surrealdb';
const db = new Surreal();
await db.connect('ws://localhost:8000');
// Upsert: insert if not exists, replace if exists
const user = await db.upsert(new RecordId('users', 'john'))
.content({
name: 'John Doe',
email: 'john@example.com',
role: 'user'
});Upsert with merge
// Safer: merge instead of replace
const user = await db.upsert(new RecordId('users', 'john'))
.merge({
last_login: DateTime.now(),
login_count: 1
});
// If user exists: only updates these fields
// If not: creates user with these fieldsBulk upsert
const users = await db.upsert(new Table('users'))
.content(userDataArray);Track changes
const result = await db.upsert(new RecordId('users', 'john'))
.content(userData)
.output('DIFF');
if (result) {
console.log('Created or updated:', result);
}Conditional upsert
const user = await db.upsert(new RecordId('users', 'john'))
.merge({ status: 'active' })
.where('verified = true');UPSERT vs CREATE vs UPDATE
// CREATE: Fails if record exists
try {
await db.create(recordId).content(data);
} catch (error) {
// Error if exists
}
// UPDATE: Fails if record doesn't exist
try {
await db.update(recordId).merge(data);
} catch (error) {
// Error if not found
}
// UPSERT: Works in both cases
await db.upsert(recordId).content(data);
// Always succeedsUse cases
Session management
// Update session or create new one
async function updateSession(sessionId: string, data: SessionData) {
return db.upsert(new RecordId('sessions', sessionId))
.merge({
...data,
last_activity: DateTime.now()
});
}Cache pattern
// Write-through cache
async function cacheSet(key: string, value: unknown) {
return db.upsert(new RecordId('cache', key))
.content({
value,
expires_at: DateTime.now().plus(Duration.parse('1h'))
});
}Counter pattern
// Increment counter or initialize
const counter = await db.upsert(new RecordId('counters', 'page_views'))
.merge({
count: 1,
last_increment: DateTime.now()
});Chaining pattern
const result = await db.upsert(new RecordId('users', 'john'))
.content(userData)
.output('AFTER')
.timeout(Duration.parse('5s'));See also
SurrealQueryable.upsert() - Method that returns UpsertPromise
CreatePromise - Create only
UpdatePromise - Update only
Query overview - All query builder classes