From 26cd5a4171038685a33e7f4c297c384a4943e43b Mon Sep 17 00:00:00 2001 From: kosabogi Date: Mon, 23 Jun 2025 11:51:28 +0200 Subject: [PATCH 1/3] Adds Update a document API example page --- .../rest-apis/update-document.md | 264 ++++++++++++++++++ docs/reference/elasticsearch/toc.yml | 1 + 2 files changed, 265 insertions(+) create mode 100644 docs/reference/elasticsearch/rest-apis/update-document.md diff --git a/docs/reference/elasticsearch/rest-apis/update-document.md b/docs/reference/elasticsearch/rest-apis/update-document.md new file mode 100644 index 0000000000000..fcfc4f76f76a3 --- /dev/null +++ b/docs/reference/elasticsearch/rest-apis/update-document.md @@ -0,0 +1,264 @@ +--- +mapped_pages: + - https://www.elastic.co/guide/en/elasticsearch/reference/8.18/docs-update.html +applies_to: + stack: all +navigation_title: Update a document +--- + +# Update a document [update-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) +- [Upsert](#upsert) +- [Doc as upsert](#scripted-upsert) + +First, let's index a simple doc: + +```console +PUT test/_doc/1 +{ + "counter" : 1, + "tags" : ["red"] +} +``` +% TESTSETUP + +To increment the counter, you can submit an update request with the +following script: + +```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): + +```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. + +```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`: + +```console +POST test/_update/1 +{ + "script" : "ctx._source.new_field = 'value_of_new_field'" +} +``` + +Conversely, this script removes the field `new_field`: + +```console +POST test/_update/1 +{ + "script" : "ctx._source.remove('new_field')" +} +``` +% TEST[continued] + +The following script removes a subfield from an object field: + +```console +PUT test/_doc/1?refresh +{ + "my-object": { + "my-subfield": true + } +} +``` + +```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`): + +```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" + } + } +} +``` + +## Update part of a document [update-part-document] + +The following partial update adds a new field to the +existing document: + +```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. + + +## Detect noop updates [detect-noop-updates] + +By default updates that don't change anything detect that they don't change +anything and return `"result": "noop"`: + +```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`: + +```console + +{ + "_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`: + +```console +POST test/_update/1 +{ + "doc": { + "name": "new_name" + }, + "detect_noop": false +} +``` + +## Upsert [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. + +```console +POST /test/_update/1 +{ + "doc": { + "product_price": 100 + }, + "upsert": { + "product_price": 50 + } +} +``` + +## Scripted upsert [scripted-upsert] + +To run the script whether or not the document exists, set `scripted_upsert` to +`true`: + +```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": {} +} +``` + +## Doc as upsert [scripted-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: + +```console +POST test/_update/1 +{ + "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. +:::: diff --git a/docs/reference/elasticsearch/toc.yml b/docs/reference/elasticsearch/toc.yml index ae5abe8cd72a5..2f56d17d7b693 100644 --- a/docs/reference/elasticsearch/toc.yml +++ b/docs/reference/elasticsearch/toc.yml @@ -104,6 +104,7 @@ toc: - file: rest-apis/searching-with-query-rules.md - file: rest-apis/shard-request-cache.md - file: rest-apis/term-vectors-examples.md + - file: rest-apis/update-document.md - file: mapping-reference/index.md children: - file: mapping-reference/document-metadata-fields.md From 196ebad5633ba4646efd777a95f7fe474cba6f16 Mon Sep 17 00:00:00 2001 From: kosabogi <105062005+kosabogi@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:19:57 +0200 Subject: [PATCH 2/3] Update docs/reference/elasticsearch/rest-apis/update-document.md Co-authored-by: Liam Thompson <32779855+leemthompo@users.noreply.github.com> --- docs/reference/elasticsearch/rest-apis/update-document.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/elasticsearch/rest-apis/update-document.md b/docs/reference/elasticsearch/rest-apis/update-document.md index fcfc4f76f76a3..b1770ac0d2691 100644 --- a/docs/reference/elasticsearch/rest-apis/update-document.md +++ b/docs/reference/elasticsearch/rest-apis/update-document.md @@ -14,8 +14,8 @@ The following examples show common use cases, such as incrementing a counter and - [Update part of a document](#update-part-document) - [Detect noop updates](#detect-noop-updates) -- [Upsert](#upsert) -- [Doc as upsert](#scripted-upsert) +- [Insert or update documents with upsert](#upsert) +- [Simplify upsert with doc_as_upsert](#doc-as-upsert) First, let's index a simple doc: From 32f352ddfab8f04d0e369bea7cc80e9dd4725d47 Mon Sep 17 00:00:00 2001 From: kosabogi Date: Tue, 24 Jun 2025 13:30:04 +0200 Subject: [PATCH 3/3] Adresses suggestions --- docs/reference/elasticsearch/rest-apis/update-document.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/elasticsearch/rest-apis/update-document.md b/docs/reference/elasticsearch/rest-apis/update-document.md index b1770ac0d2691..124d7fcc46fa9 100644 --- a/docs/reference/elasticsearch/rest-apis/update-document.md +++ b/docs/reference/elasticsearch/rest-apis/update-document.md @@ -200,7 +200,7 @@ POST test/_update/1 } ``` -## Upsert [upsert] +## Insert or update documents with upsert [upsert] An upsert operation lets you update an existing document or insert a new one if it doesn't exist, in a single request. @@ -218,7 +218,7 @@ POST /test/_update/1 } ``` -## Scripted upsert [scripted-upsert] +## Run a scripted upsert [scripted-upsert] To run the script whether or not the document exists, set `scripted_upsert` to `true`: @@ -243,7 +243,7 @@ POST test/_update/1 } ``` -## Doc as upsert [scripted-upsert] +## Simplify upsert with 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`