-
Notifications
You must be signed in to change notification settings - Fork 192
Update sub-document or attributes with query #1586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Why not...
|
Yes updating the whole document works but here my point is to update some parts of the document only (what we can do with an update query, cf https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/update.html) My use case is, there are multiple processes that needs to update some attributes only on the same document, and updating the whole document will allow some race conditions and potentially data loss if 2 processes persist the document at the same time. |
Can you show me an example of this? Are you referring to sub-doc mutations? That's not supported in spring data couchbase.
I'm not 100% sure that UPDATE on different parts of the document will avoid that. I'm checking with folks that would know. You can certainly do all those three examples in https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/update.html, because they are just setting a simple attributes to a value. String, Long, long, integer etc. are all valid args to methods. But in your case, you are setting a Person which would require a json arg. If you provide json for the arg, it should work. GsonBuilder can be used for creating Json from arbitrary java objects
If your entity has an @Version, spring-data-couchbase will use the CAS to do optimistic locking - it will throw an exception if the cas in the server does not match the cas of the incoming update. Another solution is to use transactions, which will automatically retry in the event of a write-write conflict (it uses CAS) |
yes I was referring to the sub-doc mutations
Let's say I have an asynchronous process that needs to update only my
Indeed but if I rename some attributes with |
Like I said, if you have an @Version, you'd get a cas-mismatch on one of the save operations. And then your application could re-read, update and write.
I don't think so. Couchbase database cannot lock part of a document for write (there is only one cas for the whole document). So to do an update of a single property, it still needs to (internally) read-update-write the whole document (the purpose of sub-doc operations is to avoid client-round-trip of the whole document, not lock part of a document). And I think internally it uses cas (at least I hope it does), and you'd get a cas-mismatch failure. I asked folks who should know, one person on the SDK team says there would be a cas-mismatch, but it's really a server behaviour, and am hoping for an answer from the server team. (if it does not use cas and does not check for cas-mismatch then there is no way to detect data loss from a write-write conflict). [Edit: I have verification that UPDATE does use cas and will generate a cas-mismatch error if it occurs]
So you have two choices - have your application leverage cas by having an @Version in your entity and by doing read-update-write. Or use transactions, which will do the read-before-write and check the cas for you. And retry on failure. Even if couchbase n1ql "UPDATE ...." internally uses sub-docs this won't help since there is only one cas for the whole document, concurrent updates of different sub-docs will still have a cas-mismatch fail and the application will still need to reread-update-write. p.s. even if "update" did lock-for-write a specific attribute on a document, your application would still need to handle the case of concurrent writes on the same attribute. (think bank-account-balance). |
If allowing the MappingCouchbaseConverter to convert an entity to json will help, then we can expose an api that does that (without requiring the entity have an id).
|
Oh I didn't know that part. So even if I'm using the update feature (mutateIn or query), internally it still read the document, update fields I specify, then save the whole document using cas-mismatch check ?
For now I can bypass the mandatory id by setting a dummy value like this : val target = CouchbaseDocument("id")
converter.write(source, target) But exposing a direct api that doesn't require that id would be better. Furthermore in order to keep things immutable, it'd be even better to expose an api that returns directly the CouchbaseDocument (or JsonObject) instead of requiring it. public CouchbaseDocument convertToDocument(final Object source) {
CouchbaseDocument target = new CouchbaseDocument();
...
return target
} |
Yes. In their words: But this should have a much shorter window in between the get() and replace(), so a cas-mismatch should be much less likely. |
Got it, thank you for the confirmation ! |
The enhancement would be to handle arbitrary (entity) objects as parameters, convert them to json using Edit: this is actually an omission in parameter handling. It needs to handle not only simple types, but also collections and non-Simple types (like Person). |
Hi @mikereiche, since this change, I'm not able to update a list with a query Here is my query :
Here is the exception :
The List is converted into a |
It looks like handling lists for named parameters was missing from the change. Work-around is to used ordered parameters instead $1, $2, $3 instead of $moderatorIds etc. |
The change also includes a fix to handle lists of non-simple types (original would give NPE for non-simple lists for both named and ordered parameters). |
Uh oh!
There was an error while loading. Please reload this page.
Hi, I'm trying to update some attributes with a custom query, but I get the following exception :
exception
Here is my document :
Here is my Person :
And here is my query :
It seems that the sdk requires a json object, so the only workaround I can think of is converting my Person with the
MappingCouchbaseConverter.write(source, target)
which will convert with correct field names and types.But this is an ugly solution, as the converter requires an
id
attribute else it'll throwAn ID property is needed, but not found
The text was updated successfully, but these errors were encountered: