Home > OS >  CosmosDB SQL API: Delete element matching criteria via partial update
CosmosDB SQL API: Delete element matching criteria via partial update

Time:11-28

I'm trying to remove a particular element matching criteria, in a nested array, when I already know the document id. For example, imagine a document like this (taken from https://devblogs.microsoft.com/cosmosdb/understanding-how-to-query-arrays-in-azure-cosmos-db/)

{
  "id": "Tim",
  "city": "Seattle",
  "gifts": [
     {
        "recipient": "Andrew",
        "gift": "blanket"
     },
     {
        "recipient": "Deborah",
        "gift": "board game"
     },
     {
        "recipient": "Chris",
        "gift": "coffee maker"
     }
  ]
}

I want to remove any element from the "gifts" array that has a recipient of "Andrew". A naieve approach is to pull the document, remove the array element, and set the new document. But that concerns me because it exposes a race condition where, during the time of pulling and updating the document, a different mutation could be made to that array, which would be lost.

I'd like to see if I can perform a partial document update to remove the array element. However, the partial document update documentation at https://learn.microsoft.com/en-us/azure/cosmos-db/partial-document-update states (for "remove"):

If the target path is an array index, it will be deleted and any elements above the specified index are shifted one position to the left.

So it seems like the only means of removing an array element via a partial document update is by its array index. But if I pull its array index and then perform the update, I have a similar race condition: what if the array is mutated between when I pull the document and when I perform the partial doc update?

I see that for partial document updates, you can do a "Conditional Update":

Conditional Update: For the aforementioned modes, it is also possible to add a SQL-like filter predicate (for example, from c where c.taskNum = 3) such that the operation fails if the pre-condition specified in the predicate is not satisfied.

I'm wondering if this is something I could use to achieve my goal.

Essentially, I think I'm looking for something like https://www.mongodb.com/docs/manual/reference/operator/update/pull/ but within the SQL API.

CodePudding user response:

the array is mutated between when I pull the document and when I perform the partial doc update

The only way to avoid concurrent updates to the same document is by doing Optimistic Concurrency. You would need to first Read the current document, obtain it's ETag, and then use that on the update operation by passing it to the CosmosItemRequestOptions:

requestOptions.setIfMatchETag("etag from the read");

Full example: https://github.com/Azure-Samples/azure-cosmos-java-sql-api-samples/blob/0ead4ca33dac72c223285e1db866c9dc06f5fb47/src/main/java/com/azure/cosmos/examples/documentcrud/async/DocumentCRUDQuickstartAsync.java#L366-L418

In that case, if there was any concurrent update that happened, you'd get a failure with status code 412, which means a concurrent update happened and you'd need to retry the operation (read, get the new etag, find the new index to remove, execute the update).

  • Related