Is it possible to upsert documents in elasticsearch based on a given field other than _id?

Viewed 432

I have an index with documents as follows

{ "StartId": "123a", "EndId": "123b", "Tag": "tag1" }
{ "StartId": "234a", "EndId": "234b", "Tag": "tag2" }
{ "StartId": "345a", "EndId": "345b", "Tag": "tag3" }
{ "StartId": "456a", "EndId": "456b", "Tag": "tag4" }

Now I have a new document { "StartId": "567a", "EndId": "567b", "Tag": "tag5" }

If StartId from new doc already exists in the index, I want to update it with the data in new doc else I want to insert the new document.

I know how to upsert by _id

POST test/_update/1
{
  "doc": {
    "name": "new_name"
  },
  "doc_as_upsert": true
}

But is it possible to upsert by any field other than _id? If yes, how can I do it?

1 Answers

No, it's not possible in one go.

doc_as_upsert is reserved for the Update API which requires an _id in the request's URI path.


You can, however, update documents without knowing the _id through the Update by query API:

POST test-index/_update_by_query
{
  "query": {
    "match_all": {}
  },
  "script": {
    "source": """
      if (ctx._source['StartId'] == params['StartId']) {
        ctx._source.putAll(params['upsertWith']);
      }
    """,
    "lang": "painless",
    "params": {
      "StartId": "567a",
      "upsertWith": {
        "name": "new_name"
      }
    }
  }
}

but upserting is impossible because ctx['_id'] is read-only. You can, however, delete documents with it.

Related