如果文档存在,如何进行rethinkdb原子更新,否则插入?

时间:2014-06-19 12:43:24

标签: rethinkdb

如果文档存在,如何进行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)之间,某些其他线程可能会插入它。

如何使此查询成为原子?

4 个答案:

答案 0 :(得分:17)

我认为解决方案正在传递

conflict="update"

到插入方法。

Als见RethinkDB documentation on insert

答案 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将覆盖现有的。

     

引用:Answers to common questions about RethinkDB

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