[[docs-update]] === Update API ++++ Update ++++ Updates a document using the specified script. [[docs-update-api-request]] ==== {api-request-title} `POST //_update/<_id>` [[docs-update-api-prereqs]] ==== {api-prereq-title} * If the {es} {security-features} are enabled, you must have the `index` or `write` <> for the target index or index alias. [[update-api-desc]] ==== {api-description-title} 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 <>. This operation: . Gets the document (collocated with the shard) from the index. . Runs the specified script. . 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). [[docs-update-api-path-params]] ==== {api-path-parms-title} ``:: (Required, string) Name of the target index. By default, the index is created automatically if it doesn't exist. For more information, see <>. `<_id>`:: (Required, string) Unique identifier for the document to be updated. [[docs-update-api-query-params]] ==== {api-query-parms-title} include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=if_seq_no] include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=if_primary_term] `lang`:: (Optional, string) The script language. Default: `painless`. include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=require-alias] include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=refresh] `retry_on_conflict`:: (Optional, integer) Specify how many times should the operation be retried when a conflict occurs. Default: 0. include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=routing] `_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. `timeout`:: + -- (Optional, <>) Period to wait for the following operations: * <> updates * <> Defaults to `1m` (one minute). This guarantees {es} waits for at least the timeout before failing. The actual wait time could be longer, particularly when multiple waits occur. -- include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=wait_for_active_shards] [[update-api-example]] ==== {api-examples-title} First, let's index a simple doc: [source,console] ---- PUT test/_doc/1 { "counter" : 1, "tags" : ["red"] } ---- // TESTSETUP To increment the counter, you can submit an update request with the following script: [source,console] ---- POST test/_update/1 { "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): [source,console] ---- POST test/_update/1 { "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. [source,console] ---- POST test/_update/1 { "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`: [source,console] ---- POST test/_update/1 { "script" : "ctx._source.new_field = 'value_of_new_field'" } ---- Conversely, this script removes the field `new_field`: [source,console] ---- POST test/_update/1 { "script" : "ctx._source.remove('new_field')" } ---- // TEST[continued] The following script removes a subfield from an object field: //// [source,console] ---- PUT test/_doc/1?refresh { "my-object": { "my-subfield": true } } ---- //// [source,console] ---- POST test/_update/1 { "script": "ctx._source['my-object'].remove('my-subfield')" } ---- // TEST[continued] 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`): [source,console] ---- POST test/_update/1 { "script": { "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }", "lang": "painless", "params": { "tag": "green" } } } ---- [discrete] ===== Update part of a document The following partial update adds a new field to the existing document: [source,console] ---- POST test/_update/1 { "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. [discrete] ===== Detect noop updates By default updates that don't change anything detect that they don't change anything and return `"result": "noop"`: [source,console] ---- POST test/_update/1 { "doc": { "name": "new_name" } } ---- // TEST[continued] If the value of `name` is already `new_name`, the update request is ignored and the `result` element in the response returns `noop`: [source,console-result] ---- { "_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`: [source,console] ---- POST test/_update/1 { "doc": { "name": "new_name" }, "detect_noop": false } ---- [[upserts]] [discrete] ===== 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: [source,console] ---- POST test/_update/1 { "script": { "source": "ctx._source.counter += params.count", "lang": "painless", "params": { "count": 4 } }, "upsert": { "counter": 1 } } ---- [discrete] [[scripted_upsert]] ===== Scripted upsert To run the script whether or not the document exists, set `scripted_upsert` to `true`: [source,console] ---- POST test/_update/1 { "scripted_upsert": true, "script": { "source": """ if ( ctx.op == 'create' ) { ctx._source.counter = params.count } else { ctx._source.counter += params.count } """, "params": { "count": 4 } }, "upsert": {} } ---- [discrete] [[doc_as_upsert]] ===== 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: [source,console] ---- POST test/_update/1 { "doc": { "name": "new_name" }, "doc_as_upsert": true } ---- [NOTE] ==== Using <> with `doc_as_upsert` is not supported. ====