Skip to main content

Advanced

Upsert, Full-Text Search, Aggregation, and Indexes.

Upsert

Insert a new record or update an existing one (by id):

const result = await admin.db('app').table('settings').upsert({
id: 'user-preferences',
theme: 'dark',
language: 'ko',
});
// result.action → "inserted" or "updated"

Upsert by Unique Field

By default, upsert matches by id. Use conflictTarget to match by any unique field instead:

const result = await admin.db('app').table('categories').upsert(
{ name: 'Tech', slug: 'tech', description: 'Technology posts' },
{ conflictTarget: 'slug' }
);
// If slug='tech' exists → update, otherwise → insert
// result.action → "inserted" or "updated"
note

The conflictTarget field must have a unique: true constraint in your schema. Non-unique fields will return a 400 Bad Request error. Composite unique indexes are not supported in v1.

Search across text fields using SQLite FTS5. Enable FTS in your config:

// edgebase.config.ts
databases: {
app: {
tables: {
posts: {
schema: { /* ... */ },
fts: ['title', 'content'], // Enable FTS on these fields
},
},
},
}
const results = await admin.db('app').table('posts').search('typescript tutorial').getList();
// results.items → ranked by relevance
// results.items[0].highlight → { title: "...<mark>TypeScript</mark> <mark>Tutorial</mark>..." }

Field Selection (Projection)

You can limit which fields are returned in query results using the fields query parameter in the REST API. This reduces payload size when you only need specific columns:

GET /api/db/app/tables/posts?fields=id,title,status

This returns only id, title, and status for each record instead of all fields.

You can combine fields with all other query parameters:

GET /api/db/app/tables/posts?fields=id,title&filter=[["status","==","published"]]&sort=createdAt:desc&limit=10
note

Field selection is a REST API feature. SDK methods currently return all fields. If you need projected queries from an SDK, use raw SQL in App Functions.

Aggregation

EdgeBase supports count() for record counting. For advanced aggregations (SUM, AVG, GROUP BY), use raw SQL in App Functions:

// functions/analytics.ts
export default defineFunction({
trigger: { type: 'http', path: '/api/functions/stats', method: 'GET' },
handler: async (context) => {
const stats = await context.admin.sql(
'posts',
'SELECT status, COUNT(*) as count FROM posts GROUP BY status',
[]
);
return Response.json(stats);
},
});

Indexes

Defining Indexes

posts: {
schema: { /* ... */ },
indexes: [
{ fields: ['status'] }, // Single field
{ fields: ['authorId', 'createdAt'] }, // Composite
{ fields: ['slug'], unique: true }, // Unique index
],
}

When to Add Indexes

  • Fields frequently used in where() filters
  • Fields used in orderBy() sorting
  • Fields used as conflictTarget in upsert (must be unique)