# Update Many API (schema)

> Change every row matching a filter in one statement with the schema update many API of API Maker - a find and an updateData in the body, the count of changed rows in the answer.

Source: https://docs.apimaker.dev/v1/docs/apis-all/schema-apis/auto-generated-schema-based-update-many-api.html

Applies the same change to every row matching `find`, in one statement of the database, and answers how many rows changed.

| | |
|---|---|
| Method | PUT |
| URL | `/api/schema/admin/mysql8/inventory/customers/update-many` |
| Body | `{ find, updateData }` |
| Query params | none |
| Answer | `data` : `{ updatedRowsCount }` |
| Databases | MongoDB, MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, TiDB, Percona |
| Cached | no (a write ; it resets the cache of the table) |
| From code | [`g.sys.db.updateMany`](/v1/examples/sys/db/updateMany.html) |
| API id | `SCHEMA_UPDATE_MANY` (groups, settings, hooks, WebSocket subscriptions) |
| The other family | [Update many as a generated API](/v1/docs/apis-all/generated-apis/auto-generated-update-many-api.html) |

!!! info "Generated (`/api/gen`) or schema (`/api/schema`) ?"
    Both families offer the same operations on the same URL pattern. The **schema APIs** read the [schema](/v1/docs/schema/schema.html) of the table : values are converted to their types, validated, encrypted, defaulted and numbered before they reach the database. The **generated APIs** are schemaless : they pass your data as it is, so a number sent as `"22"` stays a string. Use the schema APIs for the tables your application writes to, and the generated APIs for quick reads and for tables without a schema.

## The URL

`/api/schema/admin/mysql8/inventory/customers/update-many` : replace `admin` with the user path of your account, `mysql8` with your instance, `inventory` with the database and `customers` with the table. The examples use this table :

| customer_id | first_name | last_name | last_update           | pincode | isActive |
|-------------|------------|-----------|-----------------------|---------|----------|
| 1           | Bob        | lin       | 2022-11-14 04: 34: 58 | 382345  | 1        |
| 2           | Alice      | Page      | 2022-10-15 02: 10: 40 | 382346  | 1        |
| 3           | Mallory    | Brown     | 2022-09-13 03: 44: 05 | 382347  | 1        |
| 4           | Eve        | Mathly    | 2022-11-12 01: 59: 33 | 382348  | 1        |
| 5           | Eve        | Page      | 2022-11-12 01: 59: 33 | 382349  | 1        |

## The call

```text
PUT /api/schema/admin/mysql8/inventory/customers/update-many
```

```json title="Body"
{
    "find": { "customer_id": { "$in": [ 2, 3 ] } },
    "updateData": { "last_name": "Brown" }
}
```

```json title="Answer"
{ "success": true, "statusCode": 200, "data": { "updatedRowsCount": 2 } }
```

- `find` takes every operator of [find](/v1/docs/apis-all/query-params/find.html) : `$in`, `$gt`, `$and`, `$or`, `$like`, dotted keys… `{}` updates every row.
- `updatedRowsCount` counts the rows the database actually changed.

## More filters

```json title="$and"
{ "find": { "$and": [ { "isActive": 1 }, { "pincode": { "$gt": 382345 } } ] }, "updateData": { "isActive": 0 } }
```

```json title="$or"
{ "find": { "$or": [ { "first_name": "Bob" }, { "first_name": "Alice" } ] }, "updateData": { "pincode": 380001 } }
```

```json title="a related table (find and join)"
{ "find": { "orders.status": "CANCELLED" }, "updateData": { "isActive": 0 } }
```

## What the schema does

- `updateData` is converted and validated like an update (types, `conversionFun`, encryption, rules) and `find` like a query, before the statement runs.
- The version check of optimistic concurrency control does not apply here : the rows are changed directly in the database, without being read first.

## Good to know

- Nothing is read back : the answer has no rows. Read them with [query](/v1/docs/apis-all/schema-apis/auto-generated-schema-based-query-for-get-data-api.html) if you need them.
- The cache of the table is reset and WebSocket subscribers are notified once for the call.

## From your code

[`g.sys.db.updateMany`](/v1/examples/sys/db/updateMany.html) makes the same call from custom APIs, hooks, events, schedulers and test cases, with the same headers and params. Pass `true` as the second argument to get the whole [response envelope](/v1/docs/apis-all/response-format.html) instead of `data`.

## Headers

Every call takes the [request headers](/v1/docs/apis-all/header/requestHeader.html) : the tokens, `x-am-response-case`, `x-am-content-type-response` (JSON, XML, YAML…), `x-am-response-object-type: make_flat`, `x-am-cache-control`, `x-am-get-encrypted-data`, `x-am-internationalization`, `x-am-tenant-username`, `x-am-meta`.

## Errors

| Code | When |
|---|---|
| `401` | The token in `x-am-authorization` is missing or invalid. |
| `403` | No group of the API user grants this API of this table, or a field of the request. |
| `404` | The instance, database or table of the URL does not exist, or the table has no schema (use `/api/gen`). |
| `400` | The query or the body is wrong : the [error messages](/v1/docs/apis-all/error-codes.html) say which key and why. |

## Related

- [All APIs at a glance](/v1/docs/apis-all/overview.html) · [Query params](/v1/docs/apis-all/query-params/query-params.html) · [Response format](/v1/docs/apis-all/response-format.html) · [Pre hooks](/v1/docs/apis-all/hooks/preHook-api.html) and [post hooks](/v1/docs/apis-all/hooks/postHook-api.html) · [Automatic caching](/v1/docs/features/automatic-caching.html)
- [Table schema](/v1/docs/schema/schema.html) : what the conversions and validations do to every write.
