Rethinkdb atomic operations

时光总嘲笑我的痴心妄想 提交于 2019-12-10 14:32:32

问题


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!


回答1:


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.




回答2:


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) 
})


来源:https://stackoverflow.com/questions/31634640/rethinkdb-atomic-operations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!