Let's say I have a document
{
id: 1,
fruits: []
}
fruits here acts as a SET
Now I want to atomically add a value to fruits array for document with primary key = 1 OR create such document if it does not exist(i.e. use SetInsert ReQL under the hood)
I also need to do the same for increment(ReQL .Add)
Obviously this can't be done in client code as it breaks atomicity and I end up with inconsistent data
I wish something like this was possible
r.table('results').insert({
id: '62c70132-6516-4279-9803-8daf407ffa5c',
counter: r.row('counter').add(1).default(0)
}, {conflict: "update"})
but it dies with "RqlCompileError: r.row is not defined in this context in"
Any help/guidance is appreciated, thanks!
This is not possible with
insert
at the moment. The other mentioned solution is not atomic because it uses a subquery. We're working on a solution for this in https://github.com/rethinkdb/rethinkdb/issues/3753 .You can however use
replace
to perform an atomic upsert:replace
will actually perform an insert if the document doesn't exist.In RethinkDB, all single-query updates are atomic. If Rethink doesn't think a particular update/replace operation will be atomic, it will throw an error and require you to add a non-atomic flag to the query. So normally, you don't have to worry too much about it. However, this is only with
update
andreplace
queries. It isn't possible to do this atomically withinsert
.You are correct that if you retrieve that document, update it client side, and then put it back in the DB that it would be a non-atomic update by nature as well.
In a single query, though, you could do the following which is effectively an upsert in the same manner you used
insert
for, but usingreplace
:...which would be atomic. Similarly, to use the add operation: