Update API

Updates a document using the specified script.

Request

POST /<index>/_update/<_id>

Description

Enables you to script document updates. The script can update, delete, or skip modifying the document. The update API also supports passing a partial document, which is merged into the existing document. To fully replace an existing document, use the index API.

This operation:

  1. Gets the document (collocated with the shard) from the index.
  2. Runs the specified script.
  3. Indexes the result.

The document must still be reindexed, but using update removes some network roundtrips and reduces chances of version conflicts between the GET and the index operation.

The _source field must be enabled to use update. In addition to _source, you can access the following variables through the ctx map: _index, _type, _id, _version, _routing, and _now (the current timestamp).

Path parameters

<index>

(Required, string) Name of the target index. By default, the index is created automatically if it doesn’t exist. For more information, see Automatically create data streams and indices.

<_id>

(Required, string) Unique identifier for the document to be updated.

Query parameters

if_seq_no

(Optional, integer) Only perform the operation if the document has this sequence number. See Optimistic concurrency control.

if_primary_term

(Optional, integer) Only perform the operation if the document has this primary term. See Optimistic concurrency control.

lang

(Optional, string) The script language. Default: painless.

refresh

(Optional, enum) If true, Elasticsearch refreshes the affected shards to make this operation visible to search, if wait_for then wait for a refresh to make this operation visible to search, if false do nothing with refreshes. Valid values: true, false, wait_for. Default: false.

retry_on_conflict

(Optional, integer) Specify how many times should the operation be retried when a conflict occurs. Default: 0.

routing

(Optional, string) Target the specified primary shard.

_source

(Optional, list) Set to false to disable source retrieval (default: true). You can also specify a comma-separated list of the fields you want to retrieve.

_source_excludes

(Optional, list) Specify the source fields you want to exclude.

_source_includes

(Optional, list) Specify the source fields you want to retrieve.

master_timeout

(Optional, time units) Specifies the period of time to wait for a connection to the master node. If no response is received before the timeout expires, the request fails and returns an error. Defaults to 30s.

timeout

(Optional, time units) Specifies the period of time to wait for a response. If no response is received before the timeout expires, the request fails and returns an error. Defaults to 30s.

wait_for_active_shards

(Optional, string) The number of shard copies that must be active before proceeding with the operation. Set to all or any positive integer up to the total number of shards in the index (number_of_replicas+1). Default: 1, the primary shard.

See Active shards.

Examples

First, let’s index a simple doc:

  1. PUT test/_doc/1
  2. {
  3. "counter" : 1,
  4. "tags" : ["red"]
  5. }

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

  1. POST test/_update/1
  2. {
  3. "script" : {
  4. "source": "ctx._source.counter += params.count",
  5. "lang": "painless",
  6. "params" : {
  7. "count" : 4
  8. }
  9. }
  10. }

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):

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "ctx._source.tags.add(params.tag)",
  5. "lang": "painless",
  6. "params": {
  7. "tag": "blue"
  8. }
  9. }
  10. }

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.

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
  5. "lang": "painless",
  6. "params": {
  7. "tag": "blue"
  8. }
  9. }
  10. }

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

  1. POST test/_update/1
  2. {
  3. "script" : "ctx._source.new_field = 'value_of_new_field'"
  4. }

Conversely, this script removes the field new_field:

  1. POST test/_update/1
  2. {
  3. "script" : "ctx._source.remove('new_field')"
  4. }

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):

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
  5. "lang": "painless",
  6. "params": {
  7. "tag": "green"
  8. }
  9. }
  10. }
Update part of a document

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

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. }
  6. }

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":

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. }
  6. }

If the value of name is already new_name, the update request is ignored and the result element in the response returns noop:

  1. {
  2. "_shards": {
  3. "total": 0,
  4. "successful": 0,
  5. "failed": 0
  6. },
  7. "_index": "test",
  8. "_type": "_doc",
  9. "_id": "1",
  10. "_version": 7,
  11. "_primary_term": 1,
  12. "_seq_no": 6,
  13. "result": "noop"
  14. }

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

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. },
  6. "detect_noop": false
  7. }
Upsert

If the document does not already exist, the contents of the upsert element are inserted as a new document. If the document exists, the script is executed:

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "ctx._source.counter += params.count",
  5. "lang": "painless",
  6. "params": {
  7. "count": 4
  8. }
  9. },
  10. "upsert": {
  11. "counter": 1
  12. }
  13. }
Scripted upsert

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

  1. POST sessions/_update/dh3sgudg8gsrgl
  2. {
  3. "scripted_upsert": true,
  4. "script": {
  5. "id": "my_web_session_summariser",
  6. "params": {
  7. "pageViewEvent": {
  8. "url": "foo.com/bar",
  9. "response": 404,
  10. "time": "2014-01-01 12:32"
  11. }
  12. }
  13. },
  14. "upsert": {}
  15. }
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:

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. },
  6. "doc_as_upsert": true
  7. }

Using ingest pipelines with doc_as_upsert is not supported.