336 lines
8.6 KiB
Plaintext
336 lines
8.6 KiB
Plaintext
[[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>`
|
|
|
|
[[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::{docdir}/rest-api/common-parms.asciidoc[tag=if_seq_no]
|
|
|
|
include::{docdir}/rest-api/common-parms.asciidoc[tag=if_primary_term]
|
|
|
|
`lang`::
|
|
(Optional, string) The script language. Default: `painless`.
|
|
|
|
include::{docdir}/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::{docdir}/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.
|
|
|
|
include::{docdir}/rest-api/common-parms.asciidoc[tag=timeoutparms]
|
|
|
|
include::{docdir}/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"]
|
|
}
|
|
--------------------------------------------------
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
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"
|
|
}
|
|
}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
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"
|
|
}
|
|
}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
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'"
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
Conversely, this script removes the field `new_field`:
|
|
|
|
[source,console]
|
|
--------------------------------------------------
|
|
POST test/_update/1
|
|
{
|
|
"script" : "ctx._source.remove('new_field')"
|
|
}
|
|
--------------------------------------------------
|
|
// 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 = 'none' }",
|
|
"lang": "painless",
|
|
"params" : {
|
|
"tag" : "green"
|
|
}
|
|
}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
[float]
|
|
===== 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"
|
|
}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
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.
|
|
|
|
[float]
|
|
===== 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",
|
|
"_type": "_doc",
|
|
"_id": "1",
|
|
"_version": 7,
|
|
"_primary_term": 1,
|
|
"_seq_no": 6,
|
|
"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
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
[[upserts]]
|
|
[float]
|
|
===== 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
|
|
}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|
|
|
|
[float]
|
|
[[scripted_upsert]]
|
|
===== Scripted upsert
|
|
|
|
To run the script whether or not the document exists, set `scripted_upsert` to
|
|
`true`:
|
|
|
|
[source,console]
|
|
--------------------------------------------------
|
|
POST sessions/_update/dh3sgudg8gsrgl
|
|
{
|
|
"scripted_upsert":true,
|
|
"script" : {
|
|
"id": "my_web_session_summariser",
|
|
"params" : {
|
|
"pageViewEvent" : {
|
|
"url":"foo.com/bar",
|
|
"response":404,
|
|
"time":"2014-01-01 12:32"
|
|
}
|
|
}
|
|
},
|
|
"upsert" : {}
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[s/"id": "my_web_session_summariser"/"source": "ctx._source.page_view_event = params.pageViewEvent"/]
|
|
// TEST[continued]
|
|
|
|
[float]
|
|
[[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
|
|
}
|
|
--------------------------------------------------
|
|
// TEST[continued]
|