Update many rows with different values
updateEach updates many rows, each with its own values, in one UPDATE ... CASE statement.
Use updateEach when many rows need different values (a sorted list, prices from a feed, names from an import). It generates one CASE expression per column instead of one UPDATE per row. When every row gets the same value, use updateMany.
const { count } = await client.users.updateEach({
by: users.id,
data: [
{ id: 1, name: 'Alice Updated', city: 'New York' },
{ id: 2, name: 'Bob Updated', city: 'Chicago' },
],
update: {
name: (row) => row.name,
city: (row) => row.city,
},
});It runs a single statement:
UPDATE users
SET
name = CASE WHEN id = 1 THEN 'Alice Updated' WHEN id = 2 THEN 'Bob Updated' ELSE name END,
city = CASE WHEN id = 1 THEN 'New York' WHEN id = 2 THEN 'Chicago' ELSE city END
WHERE id IN (1, 2)by is a Drizzle column instance (users.id), not a column key. Each data row must carry its by value.
Limit and return the updated rows
where is combined with the generated by IN (...) predicate, so only eligible rows change. select returns scalar columns of the updated rows:
const { data } = await client.users.updateEach({
by: users.id,
data: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
],
update: { name: (row) => row.name },
where: { active: true }, // only active users
select: { id: true, name: true, email: true },
});Compute values in SQL
A callback can return a Drizzle SQL value. It goes into that row's CASE branch as is, so it can call SQL functions or reference columns:
import { sql } from 'drizzle-orm';
const { count } = await client.users.updateEach({
by: users.id,
data: [
{ id: 1, name: 'alice' },
{ id: 2, name: 'bob' },
],
update: {
name: (row) => sql`upper(${row.name})`,
city: () => sql`coalesce(${users.city}, 'Unknown')`,
},
});Callbacks also accept atomic updates, array updates, and JSONB path updates.
Edge cases
Reference
| Option | Type | Required | Description |
|---|---|---|---|
by | TableColumn | Yes | Drizzle column instance used to match rows (e.g., users.id) |
data | Row[] | Yes | Source rows containing the by value plus any extra fields |
update | object | Yes | Per-column callbacks (row) => value | SQL that resolve each row's new value |
where | WhereArg | No | Extra filter combined with the generated by IN (...) predicate |
select | SelectInput | No | Scalar projection for returned rows |
onEmpty | 'return' | 'throw' | No | Behavior when data is empty. Defaults to 'return' |
meta | Meta | No | Custom metadata forwarded to hooks |
Returns Promise<BatchResult<T>>: { count, data? }, with data when select is set and the driver supports RETURNING.
Use updateMany when | Use updateEach when |
|---|---|
| All matching rows get the same value | Each row needs a different value |
A WHERE filter is enough | You need per-row logic in callbacks |