How to get CAS value while performing an update using couchbase subdocument api?

I want to perform update on documents. I am using couchbase subdocument api to update the documents.

While performing the update,I only have the document id at hand. However to get the current Cas value I have to perform a get to the couchbase.

My update looks like: PrimaryBucket.mutateIn(document_id).upsert(“path1”,“updatevalue1”).upsert(“path2”,“updatevalue2”)

To handle optimistic locking, i want to use “mutateIn(id).withCas()”

While performing the update,I only have the document id at hand. However to get the current Cas value I have to perform a get to the couchbase. Is there a way to avoid fetching the whole document in order to only get the cas value to perform the update. Is this the correct approach?

Hi @Reetika_Ojha, welcome to the forum!

Looks like Couchbase SDK developer @graham.pople already responded to your question on StackOverflow.

Can you elaborate on why a normal update without CAS is not sufficient? Maybe we can help you find a better approach. I’m having a hard time understanding why you’d want to do a optimistic locking if all you know is the document ID… seems like in that case a normal update without CAS might be more appropriate.

Thanks,
David N.

Hi David,

I can’t disclose the actual problem statement here. However, I will try to explain my use case with a similar situation.

Use case:
I have the details of a an order placed by a user. the details like order number(unique identifier), order price are fixed and will not be changed. However the state of order(PLACED/SHIPPED/DELIVERED/RETURNED) and stateUpdateTimestamp can be changed.

There is an array of queries which a user can place for that order. Here operation can be performed on the query by multiple departments in async mode.

{

ordernumber:'order12345',
orderprice:2000.0,
orderstate:[
{
name:'PLACED',
stateUpdateTimestamp:'2018-05-01-22.23.23.123456'
},
{
name:'SHIPPED',
stateUpdateTimestamp:'2018-05-01-22.24.23.123456'
},
{
name:'DELIVERED',
stateUpdateTimestamp:'2018-05-01-22.25.23.123456'
}
]
query:[
{
id:'query1',
operation:'placed an exchange',
status:'RESOLVED',
queryUpdatedTimestamp:'2018-05-01-22.25.23.123456'
}
{
id:'query2',
operation:'checking if wrong item dispatched',
status:'INTRANSIT',
queryUpdatedTimestamp:'2018-05-01-23.25.23.123456'
}
]	

}

In the above use case we have following scenarios where two simultaneous updates may be performed on same part of document. In both the scenarios I have the ‘ordernumber’ provided by user to identify the document.

  1. The ‘orderstate’ array can be updated simultaneously by two threads. According to subdocument api, two concurrent subdoc arrayAppend operations to the same array will both succeed, never overwriting the other. So in this case two concurrent appends to ‘orderstate’ will not result in loss of an ‘orderstate’ entry. Please confirm on this.
  2. More than one threads can concurrently update the ‘query.operation’ and ‘query.queryUpdatedTimestamp’ field of a query. Here I need the cas value to be checked.

Please share your opinion on the solution and confirm our understanding.

Hey @Reetika_Ojha

That seems reasonable to me. arrayAppend works as you say, that’s safe. And for two clients concurrently modifying the same field, yes CAS will prevent that.

There are other solutions though, maybe you could make both “operation” and “queryUpdatedTimestamp” fields arrays, and arrayAppend into them? Then just read the last value from there as the current queryUpdatedTimestamp. Just a minor optimisation to eliminate the initial CAS fetch. Depending on how often those fields are updated you may need to periodically compact them.