如果文档存在,如何进行rethinkdb原子更新,否则插入?
我想做的事情如下:
var tab = r.db('agflow').table('test');
r.expr([{id: 1, n: 0, x: 11}, {id: 2, n: 0, x: 12}]).forEach(function(row){
var _id = row('id');
return r.branch(
tab.get(_id).eq(null), // 1
tab.insert(row), // 2
tab.get(_id).update(function(row2){return {n: row2('n').add(row('n'))}}) // 3
)})
然而,这不是完全原子的,因为在我们检查文档是否存在(1)和插入它(2)之间,某些其他线程可能会插入它。
如何使此查询成为原子?
答案 0 :(得分:17)
答案 1 :(得分:3)
要使内部部分成为原子,您可以使用replace
:
tab.get(_id).replace(function(row2){
return r.expr({id: _id, n: row2('n').add(row('n'))})
.default(row)
})
使用replace
是目前使用非平凡更新操作执行完全原子upsert的唯一方法。
答案 2 :(得分:1)
这是一个称为“upsert”的标准数据库操作。
RethinkDB是否支持upserts?
塞尔吉奥的另一个问题 Tulentsev。第一次公开发布不包括支持 upserts,但现在可以通过传递额外的标志来插入:
r.table('marvel').insert({ superhero: 'Iron Man', superpower: 'Arc Reactor' }, {upsert: true}).run()
设置为true时,新文档 来自insert将覆盖现有的。
答案 3 :(得分:1)
好的,我知道该怎么做。
解决方案是首先尝试insert
,如果失败,我们会update
:
var tab = r.db('agflow').table('test');
tab.delete();
r.expr([{id: 1, n: 0, x: 11}, {id: 2, n: 0, x: 12}]).forEach(function(row){
var _id = row('id');
var res = tab.insert(row);
return r.branch(
res('inserted').eq(1),
res,
tab.get(_id).update(function(row2){return {n: row2('n').add(1)}})
)})