Update Document API

The Update API allows to delete a document based on the existent content of a document. The operation gets the current document from the index, merges the new data with the data in the current document, optionally it can also run a script, and indexes back the result. It internally and automatically uses versioning to make sure this operation is atomic.

If the document does not already exist, Xapiand will return 404 by default. This can be changed by passing upsert as a query param, in this event, the body of the request will be added as a new document, the exact same way as the Index API does it, just just the little extra overhead of trying to retrieve the current document first.

For example, let’s index a simple doc:

PUT /twitter/tweet/1
{
  "user": "Kronuz",
  "post_date": "2019-03-22T14:35:26",
  "message": "Trying out Xapiand",
  "likes": 0,
  "hashtags": ["#xapiand"]
}

The result of the above index operation is:

{
  "user": "Kronuz",
  "post_date": "2019-03-22T14:35:26",
  "message": "Trying out Xapiand",
  "likes": 0,
  "hashtags": [
    "#xapiand"
  ],
  "_id": 1,
  "_version": 1,
  "#docid": 1,
  "#shard": 1
}

PUT /twitter/tweet/1 is not the same as PUT /twitter/tweet/1/, the former creates a document with ID 1 inside index /twitter/tweet/ while the later creates the index /twitter/tweet/1/ itself. Trailing slashes are important.

Merging

The following update adds a new field to the existing document by merging the passed fields (simple recursive merge, inner merging of objects, replacing core “keys/values”and arrays):

UPDATE /twitter/tweet/1
{
  "title": "Xapiand Rocks!"
}

As expected, the result of the merge operation is:

{
  "user": "Kronuz",
  "post_date": "2019-03-22T14:35:26",
  "message": "Trying out Xapiand",
  "likes": 0,
  "hashtags": [
    "#xapiand"
  ],
  "title": "Xapiand Rocks!",
  "_id": 1,
  "_version": 12,
  "#docid": 1,
  "#shard": 1
}

To fully replace the existing document, the Index API should be used instead.

Scripting

Now, we can execute a script that would increment the number of likes:

UPDATE /twitter/tweet/1
{
  "_script": "_doc.likes = _old_doc.likes + 1"
}

We can add a tag to the list of hashtags (if the tag exists, it still gets added, since this is a list):

UPDATE /twitter/tweet/1
{
  "_script": {
    "_body": "_doc.hashtags.append(tag)",
    "_params": {
      "tag": "#trying"
    }
  }
}

We can remove a tag from the list of hashtags:

UPDATE /twitter/tweet/1
{
  "_script": {
    "_body": "_doc.hashtags.erase(tag)",
    "_params": {
      "tag": "#trying"
    }
  }
}

We can also programmatically add a new field to the document:

UPDATE /twitter/tweet/1
{
  "_script": {
    "_body": "_doc[field] = value",
    "_params": {
      "field": "new_field",
      "value": "value_of_new_field"
    }
  }
}

Or remove a field from the document:

UPDATE /twitter/tweet/1
{
  "_script": {
    "_body": "_doc.erase(field)",
    "_params": {
      "field": "new_field",
    }
  }
}

See the Scripting section for more details about scripts and the scripting language.

Commit

By passing commit query param to the request, you can ensure the operation returns once the document changes have been committed to the primary shard.

Try limiting the use of commit as it will hit performance.

Optimistic Concurrency Control

Delete operations can be made optional and only be performed if the last current document version matches the passed version in the query param. If a mismatch is detected, the operation will result in a 409 Conflict HTTP response code. See Versioning for more details.