---
title: Update a document
description: The Update API enables you to script document updates, allowing you to update, delete, or skip modifying a document. The following examples show common...
url: https://www.elastic.co/docs/reference/elasticsearch/rest-apis/update-document
products:
  - Elasticsearch
applies_to:
  - Elastic Stack: Generally available
---

# Update a document
The [Update API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-update) enables you to script document updates, allowing you to update, delete, or skip modifying a document.
The following examples show common use cases, such as incrementing a counter and adding or removing elements from a list, as well as how to:
- [Update part of a document](#update-part-document)
- [Detect noop updates](#detect-noop-updates)
- [Insert or update documents with upsert](#upsert)
- [Simplify upsert with doc_as_upsert](#doc-as-upsert)

First, let's index a simple doc:
```json

{
  "counter" : 1,
  "tags" : ["red"]
}
```

To increment the counter, you can submit an update request with the
following script:
```json

{
  "script" : {
    "source": "ctx._source.counter += params.count",
    "lang": "painless",
    "params" : {
      "count" : 4
    }
  }
}
```

Similarly, you could use and update script to add a tag to the list of tags
(this is just a list, so the tag is added even it exists):
```json

{
  "script": {
    "source": "ctx._source.tags.add(params.tag)",
    "lang": "painless",
    "params": {
      "tag": "blue"
    }
  }
}
```

You could also remove a tag from the list of tags. The Painless
function to `remove` a tag takes the array index of the element
you want to remove. To avoid a possible runtime error, you first need to
make sure the tag exists. If the list contains duplicates of the tag, this
script just removes one occurrence.
```json

{
  "script": {
    "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
    "lang": "painless",
    "params": {
      "tag": "blue"
    }
  }
}
```

You can also add and remove fields from a document. For example, this script
adds the field `new_field`:
```json

{
  "script" : "ctx._source.new_field = 'value_of_new_field'"
}
```

Conversely, this script removes the field `new_field`:
```json

{
  "script" : "ctx._source.remove('new_field')"
}
```

The following script removes a subfield from an object field:
```json

{
  "script": "ctx._source['my-object'].remove('my-subfield')"
}
```

Instead of updating the document, you can also change the operation that is
executed from within the script. For example, this request deletes the doc if
the `tags` field contains `green`, otherwise it does nothing (`noop`):
```json

{
  "script": {
    "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
    "lang": "painless",
    "params": {
      "tag": "green"
    }
  }
}
```


## Update part of a document

The following partial update adds a new field to the
existing document:
```json

{
  "doc": {
    "name": "new_name"
  }
}
```

If both `doc` and `script` are specified, then `doc` is ignored. If you
specify a scripted update, include the fields you want to update in the script.

## Detect noop updates

By default updates that don't change anything detect that they don't change
anything and return `"result": "noop"`:
```json

{
  "doc": {
    "name": "new_name"
  }
}
```

If the value of `name` is already `new_name`, the update
request is ignored and the `result` element in the response returns `noop`:
```js
{
   "_shards": {
        "total": 0,
        "successful": 0,
        "failed": 0
   },
   "_index": "test",
   "_id": "1",
   "_version": 2,
   "_primary_term": 1,
   "_seq_no": 1,
   "result": "noop"
}
```

You can disable this behavior by setting `"detect_noop": false`:
```json

{
  "doc": {
    "name": "new_name"
  },
  "detect_noop": false
}
```


## Insert or update documents with upsert

An upsert operation lets you update an existing document or insert a new one if it doesn't exist, in a single request.
In this example, if the product with ID `1` exists, its price will be updated to `100`. If the product does not exist, a new document with ID `1` and a price of `50` will be inserted.
```json

{
  "doc": {
    "product_price": 100
  },
  "upsert": {
    "product_price": 50
  }
}
```


## Run a scripted upsert

To run the script whether or not the document exists, set `scripted_upsert` to
`true`:
```json

{
  "scripted_upsert": true,
  "script": {
    "source": """
      if ( ctx.op == 'create' ) {
        ctx._source.counter = params.count
      } else {
        ctx._source.counter += params.count
      }
    """,
    "params": {
      "count": 4
    }
  },
  "upsert": {}
}
```


## Simplify upsert with doc_as_upsert

Instead of sending a partial `doc` plus an `upsert` doc, you can set
`doc_as_upsert` to `true` to use the contents of `doc` as the `upsert`
value:
```json

{
  "doc": {
    "name": "new_name"
  },
  "doc_as_upsert": true
}
```

<note>
  Using [ingest pipelines](https://www.elastic.co/guide/en/elasticsearch/reference/8.18/ingest.html) with `doc_as_upsert` is not supported.
</note>