## On this page

Medplum offers three FHIR operations that can be used to update data:

- `update`: Replaces the entire resource
- `upsert`: Replaces the entire resource and creates a new one if the specified resource is not found
- `patch`: Updates only the specific element(s) that are requested.

## Update Operation

The `update` operation is performed by sending a `PUT` request, which will create an entirely new version of your resource, rewriting every element. When sending an update request you must include the `resourceType` and the `id` of the resource you are updating, as well as the updated resource itself in the body of the request.

Medplum provides the `updateResource` method on the `MedplumClient` which implements the `update` operation. The function takes the updated resource as an argument.

### Example: Updating a Resource

- Typescript
- CLI
- cURL

```ts
const updatedPatient = await medplum.updateResource({
  resourceType: 'Patient',
  id: 'homer-simpson',
  name: [{ family: 'Simpson', given: ['Homer'] }],
});
```

```bash
medplum put Patient/homer-simpson '{"resourceType":"Patient","id":"homer-simpson","name":[{"family":"Simpson","given":["Homer"]}]}'
```

```bash
curl -X PUT 'https://api.medplum.com/fhir/R4/Patient/homer-simpson' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json' \
  -d {"resourceType":"Patient","id":"homer-simpson","name":[{"family":"Simpson","given":["Homer"]}]}
```

## Upsert Operation

The `upsert` operation also sends a `PUT` request, updating your entire resource. However, instead of taking the `id`, it allows you to use a search query with [FHIR search parameters](/content/docs/search/basic-search#search-parameters/index.html) to find the resource you want to update.

- If the search query resolves to a single resource, that resource will be updated.
- If it does not find a matching resource, one will be created from the given data.
- If multiple matches are found, an error will be returned. In this case, more specific search criteria are required to unambiguously identify the resource to be updated or created.

Medplum provides the `upsertResource` method on the `MedplumClient`, which implements the `upsert` operation. The function takes a `resource` and a FHIR search query to find the resource to be updated.

### Example: Upserting a Resource

- Typescript
- CLI
- cURL

```ts
await medplum.upsertResource(
  { resourceType: 'Patient', id: 'homer-simpson', name: [{ family: 'Simpson', given: ['Homer'] }] },
  'Patient?family="Simpson"&given="Homer"'
);
```

```bash
medplum put Patient?family="Simpson"&given="Homer" '{"resourceType":"Patient","id":"homer-simpson","name":[{"family":"Simpson","given":["Homer"]}]}'
```

```bash
curl -X PUT 'https://api.medplum.com/fhir/R4/Patient?family="Simpson"&given="Homer' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json' \
  -d {"resourceType":"Patient","id":"homer-simpson","name":[{"family":"Simpson","given":["Homer"]}]}
```

### Preventing Lost Updates with Version Checking

When updating resources in a multi-user environment, it's important to prevent **lost updates** that can occur when multiple clients update the same resource concurrently. Without version checking, the last write wins, which can overwrite changes made by other users.

To prevent this, you can use the `If-Match` header (or `ifMatch` option) to specify the expected version of the resource. If the resource's current version doesn't match, the update will fail with a `412 Precondition Failed` error.

### Example: Safe Update with Version Checking

- Typescript
- cURL

```ts
// Read the current version of the resource
const currentPatient = await medplum.readResource('Patient', 'homer-simpson');

// Update with version checking to prevent lost updates
// If another user updated the resource, this will throw an error with status 412
await medplum.updateResource(
  {
    resourceType: 'Patient',
    id: 'homer-simpson',
    name: [{ family: 'Simpson', given: ['Homer', 'Jay'] }],
  },
  {
    headers: {
      'If-Match': currentPatient.meta?.versionId ? `W/"${currentPatient.meta.versionId}"` : '',
    },
  }
);
```

```bash
# First, read the current resource to get its versionId
curl -X GET 'https://api.medplum.com/fhir/R4/Patient/homer-simpson' \
  -H 'authorization: Bearer $ACCESS_TOKEN'

# Then update with If-Match header to ensure the resource hasn't changed
curl -X PUT 'https://api.medplum.com/fhir/R4/Patient/homer-simpson' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json' \
  -H 'If-Match: W/"abc123"' \
  -d '{"resourceType":"Patient","id":"homer-simpson","name":[{"family":"Simpson","given":["Homer","Jay"]}]}'
```

**For transaction bundles**, you can use version checking with `ifMatch` in bundle entry requests. See the [Version Checking in Transaction Bundle](/content/docs/fhir-datastore/fhir-batch-requests#preventing-lost-updates-with-version-checking/index.html) section for details.

## Patch Operation

The `patch` operation is performed by sending an HTTP `PATCH` request, which updates only the specified elements in your resource. When sending a `patch` operation, you must include the `resourceType` and the `id` of the resource, as well as the patch body, containing the operation, path, and value.

Medplum provides the `patchResource` method on the `MedplumClient` which implements the `patch` operation. The function takes the `resourceType`, `id`, and an array of `PatchOperations`. A `PatchOperation` details the updates that will be made to your resource, and has three required fields: `op`, `path`, and `value`. The `op` is the actual operation that will be performed, the `path` is the path to the element on the resource that is being updated, and the `value` is the new value for the element at the given path.

The `PatchOperation` below sends an `add` operation to the `name` of the [`Patient`](/content/docs/api/fhir/resources/patient/index.html) with our newly created name. The `add` operation can be used even if the patient already has a name, as it will replace any value it finds at the given path.

### Example: Patching a Resource

- Typescript
- CLI
- cURL

```ts
const patchedPatient = await medplum.patchResource('Patient', 'homer-simpson', [
  { op: 'test', path: '/meta/versionId', value: patient.meta?.versionId },
  { op: 'add', path: '/name', value: [{ family: 'Simpson', given: ['Homer'] }] },
]);
```

```bash
medplum patch Patient/homer-simpson '[{"op":"add","path":"/name","value":[{"family":"Simpson","given":["Homer"]}]}]'
```

```bash
curl -X PATCH 'https://api.medplum.com/fhir/R4/Patient/homer-simpson' \
  -H 'authorization: Bearer $ACCESS_TOKEN' \
  -H 'content-type: application/fhir+json' \
  -d '[{"op":"add","path":"/name","value":[{"family":"Simpson","given":["Homer"]}]}]'
```

### Preventing Race Conditions

In the TypeScript patch example, a second `PatchOperation` is included:

`{ op: 'test', path: '/meta/versionId', value: patient.meta?.versionId }`

This is a test to prevent race conditions. This will cause the `patch` to fail if the resource on the server has a different `versionId` than the one you are sending. **It is strongly recommended to include this test on all `patch` operations.**

- [Update Operation](/content/docs/fhir-datastore/updating-data#update-operation/index.html)
- [Upsert Operation](/content/docs/fhir-datastore/updating-data#upsert-operation/index.html)
- [Preventing Lost Updates with Version Checking](/content/docs/fhir-datastore/updating-data#preventing-lost-updates-with-version-checking/index.html)
- [Patch Operation](/content/docs/fhir-datastore/updating-data#patch-operation/index.html)
