elasticsearch/docs/reference/docs/update.asciidoc
Adam Michalik a1056f1e00
Docs: Correct ctx.op value to valid 'noop' (#89391)
The documentation mentions the `noop` value ("Otherwise it does nothing (`noop`)"), however, the value used in the example script is `none`. This change corrects the value in the example script to `noop`.
2022-08-17 09:52:34 -05:00

375 lines
7.8 KiB
Text

[[docs-update]]
=== Update API
++++
<titleabbrev>Update</titleabbrev>
++++
Updates a document using the specified script.
[[docs-update-api-request]]
==== {api-request-title}
`POST /<index>/_update/<_id>`
[[docs-update-api-prereqs]]
==== {api-prereq-title}
* If the {es} {security-features} are enabled, you must have the `index` or
`write` <<privileges-list-indices,index privilege>> 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 <<docs-index_,`index` API>>.
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}
`<index>`::
(Required, string) Name of the target index. By default, the index is created
automatically if it doesn't exist. For more information, see <<index-creation>>.
`<_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, <<time-units, time units>>)
Period to wait for the following operations:
* <<dynamic-mapping,Dynamic mapping>> updates
* <<index-wait-for-active-shards,Waiting for active shards>>
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 <<ingest,ingest pipelines>> with `doc_as_upsert` is not supported.
====