better-drizzle

This page is PostgreSQL only.

JSONB updates

Update nested keys of a PostgreSQL JSONB column with typed dot paths instead of rewriting the whole document.

Added in 0.3.0

Use JSONB path updates when you change a few keys of a jsonb document and want to keep the rest of it, without a read-modify-write round trip.

Set a path to a JSON value. There is no set envelope: the value assigned to each path is the value written there. On a column declared with $type<T>() (see define the JSON shape), every path and value is checked against T at compile time.

await client.accounts.update({
	where: { id },
	data: { settings: { 'plan.tier': 'pro', 'plan.seats': 25 } },
});

Paths compile to chained jsonb_set(..., true) calls with JSON-encoded bound parameters.

Choose the update shape

Goalsettings valueEffect
Set nested paths{ 'plan.tier': 'pro', 'plan.seats': 25 }Changes those keys and keeps the rest of the document.
Set a top-level key{ json: { nickname: 'Ada' } }Changes nickname without replacing the document.
Write JSON null{ json: { nickname: null } }Keeps the key with a JSON null value.
Replace the documentA complete AccountSettings objectReplaces the whole value. An empty {} also replaces it.

Every shorthand key must contain a dot. A top-level key goes inside { json: { ... } }; the wrapper must be the only key and contain at least one path.

Use paths in every write

Write APIPut the path assignment in
update, updateManydata: { settings: { 'plan.seats': 25 } }
updateEachupdate: { settings: (row) => ({ 'plan.seats': row.seats }) }
upsertupdate: { settings: { 'plan.seats': 25 } } (conflict branch)
upsertManyupdate: { settings: { 'plan.seats': 25 } } or an update callback (conflict branch)

upsertMany with update: 'all' or update: ['settings'] copies the proposed full document; use an object or a callback for a path update. create and createMany insert complete documents.

Delete keys, merge, or increment

There are no structured operators for deleting a key, merging an object, incrementing a number, or changing array elements. null writes JSON null instead of deleting the key. Pass a Drizzle sql expression as the whole column value:

import { sql } from 'drizzle-orm';

await client.accounts.update({
	where: { id },
	data: { settings: sql`${accounts.settings} - 'referrer'` },
});

Edge cases

On this page