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:
r.table('results').get('62c70132-6516-4279-9803-8daf407ffa5c')
.replace({
id: '62c70132-6516-4279-9803-8daf407ffa5c',
counter: r.row('counter').add(1).default(0)
})
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
and replace
queries. It isn't possible to do this atomically with insert
.
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 using replace
:
r.table('FruitStore')
.get(1)
.replace({
id : 1,
fruits : r.row('fruits').default([]).append('orange')
})
...which would be atomic. Similarly, to use the add operation:
r.table('FruitStore')
.get(1)
.replace({
id : 1,
count : r.row('count').default(0).add(1)
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With