> ## Documentation Index
> Fetch the complete documentation index at: https://docs.riggery.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# State update

> Change the same fields on every matching record.

**State update** changes the same fields on every record that matches a filter. Other fields stay as they are.

To add records or replace a whole record, use [State upsert](/graph/tools/state-upsert).

<h2 id="set">
  Filter and values
</h2>

Connect a previous node — usually [Code](/graph/tools/code) — that returns:

```json theme={null}
{
  "collection": "rates",
  "where": [{ "path": "lane", "eq": "E" }],
  "set": [{ "path": "status", "value": "C" }]
}
```

This sets `status` to `C` on every record in `rates` whose `lane` is `E`.

`where` uses the same filters as [State query](/graph/tools/state-query). You need at least one condition. An empty filter is an error, not “all records”.

`set` is the new value for each field. If you set an object, it replaces what was there. Field names are dotted keys (`status`, `price.amount`).

If this JSON already has `collection`, you can leave **Collection** empty on this node.

An Agent can send the same `where` and `set` when it uses this tool.

<h2 id="input">
  Input
</h2>

Inspector **Settings**. Empty-field rules for the Graph: [Previous nodes](/graph/previous-nodes). This inspector has no **Insert value**.

On an Agent Tool, **Collection** can be **Agent decides** or **Fixed**.

| Field          | Required | Empty           | Notes                                              |
| -------------- | -------- | --------------- | -------------------------------------------------- |
| **Collection** | No       | Previous Result | Needed if the previous Result has no `collection`. |

Without a previous Result and without `where` / `set` from the Agent, the step fails.

<h2 id="output">
  Output
</h2>

On the next node, **Previous nodes** lists **`State update`: Result** (`{{State update.text}}` while the name is unique).

| Output | In menu | Type | Next node gets                                                                                                           |
| ------ | ------- | ---- | ------------------------------------------------------------------------------------------------------------------------ |
| Result | Yes     | Text | A status line such as `Updated 200 record(s) in "rates".` Not the records. Zero matches still succeeds with `Updated 0`. |

<h2 id="limits">
  Limits
</h2>

At most 8 filters in `where` and 8 fields in `set`. New values together may be at most 64000 bytes.

At most 5000 matching records. If more match, the step fails and writes nothing. Run the same `set` again with a tighter `where`, then the next slice, until every group is at or under 5000.

Example — 8000 rows across two lanes, same new `status`:

```json theme={null}
{
  "collection": "rates",
  "where": [{ "path": "lane", "eq": "E" }],
  "set": [{ "path": "status", "value": "C" }]
}
```

```json theme={null}
{
  "collection": "rates",
  "where": [{ "path": "lane", "eq": "W" }],
  "set": [{ "path": "status", "value": "C" }]
}
```

If one value still matches too many, add another field (`eq`, `in`, or a range `gte` / `lt`).

If a field cannot be written because a value on the way is not an object, the step fails and writes nothing. Example: setting `price.amount` when `price` is already the string `"flat"`.

If the collection has a schema, each new value must match that field. A mismatch fails and writes nothing.
