---
id: find-and-replace
title: 'Find and Replace'
description: 'Conditionally replace substrings in text attributes and swap references in multi-value relations across many assets at once.'
sidebar_label: 'Find and Replace'
sidebar_position: 6
tags: ['api', 'bulk', 'asset', 'update']
---

`find` / `replace` is an update form that changes an attribute **only where the
sought value is already present**. It works on scalar text attributes and on
multi-value relations, and it is the tool of choice for mass edits where a
blanket assignment would be wrong.

```json
{
  "from": "<asset type or OID token>",
  "where": { /* optional narrowing */ },
  "update": {
    "<Attribute>": { "find": "<value>", "replace": "<value>" }
  }
}
```

## On Scalar Text Attributes

For `Text` and `LongText` attributes, `find` matches a **substring** and
`replace` substitutes it in place. The surrounding text is preserved.

```yaml
from: Story
where:
 Scope: Scope:1800
update:
 Name:
  find: Product-To-Be-Named-Later
  replace: Awesum.ly
```

Given two Stories named:

```text
Product-To-Be-Named-Later is a marketing approved product name!
Product-To-Be-Named-Later is for math wizards who want to do their calculations in the cloud.
```

they become:

```text
Awesum.ly is a marketing approved product name!
Awesum.ly is for math wizards who want to do their calculations in the cloud.
```


:::warning Substring, not token
`find` is a plain substring match. Replacing `Cog` also rewrites `Cogent` and
`Cognition`. There is no word-boundary or regular-expression support. Preview
the change first — see [Preview mode](/apis/asset-bulk/preview-mode).
:::

Matching is exact and case-sensitive in every test in the suite; no
case-insensitive variant is exercised.

## On Multi-Value Relations

For a relation, `find` and `replace` take references, and the semantics become
"swap this reference for that one, but only where the first is already
assigned".

```yaml
from: Story
where:
 Scope: Scope:1800
update:
 Owners:
  find: Member:20
  replace: Member:1575
```

This projects to a per-asset command that keeps the `find`/`replace` pair
intact rather than resolving it to `add`/`remove` — the decision is deferred to
processing, where each asset's current membership is known:

```json
[
  {
    "@33e9c481-29c7-4639-bb92-739be91f3da7": {
      "oid": "Task:1489",
      "update": { "Owners": { "find": "Member:20", "replace": "Member:1575" } }
    }
  },
  {
    "@e3991edc-106e-4d5a-947d-e0421e250faa": {
      "oid": "Task:1490",
      "update": { "Owners": { "find": "Member:20", "replace": "Member:1575" } }
    }
  }
]
```

If `Task:1490` does not have `Member:20` as an owner, it is left untouched —
`Member:1575` is **not** added to it.


:::warning `assetsModified` counts matched assets, not changed ones
An asset lacking the `find` value is left untouched — but it is still
**counted in `assetsModified`**, exactly as if it had been changed. The count
tells you how many assets the command addressed, not how many it altered.
There is no response field that distinguishes the two; read the assets back if
you need to know what actually changed.
:::

## Why Not `add` / `remove`

```json title="Wrong for a conditional swap"
{
  "from": "Story",
  "where": { "Scope": "Scope:1800" },
  "update": { "Owners": { "remove": "Member:20", "add": "Member:1575" } }
}
```

This assigns `Member:1575` to **every** matched Story, including those that
never had `Member:20`. Use `find` / `replace` when the replacement should be
conditional on the original value.

## Related Topics

- [Updating assets](/apis/asset-bulk/updating-assets)
- [Updating multi-value relations](/apis/asset-bulk/relation-updates)
- [Preview mode](/apis/asset-bulk/preview-mode)
