使用 RethinkDB 正确更新插入(原子更新计数器字段或插入文档)

Proper Upsert (Atomic Update Counter Field or Insert Document) with RethinkDB

在查看 RethinkDB 上的一些 SO 问题和问题后 github,我未能得出明确的结论,如果原子 Upsert 是可能的?

基本上我想使用 Redis 执行与 ZINCRBY 相同的操作。

If member does not exist in the sorted set, it is added with increment as its score (as if its previous score was 0.0). If key does not exist, a new sorted set with the specified member as its sole member is created.

当前的实现似乎与我使用过的几乎所有数据库都不同。随着数据被替换或插入未更新。这是一个简单的用例,比如更新上次访问、更新点击次数、更新产品数量。所以我一定遗漏了一些非常明显的东西,因为我看不到一个简单的方法来做到这一点。

是的,这是可能的。在键 get 之后,执行原子 replace。这样的事情可能会奏效:

function set_or_increment_score(player, points){
  return r.table('scores').get(player).replace(
    row =>
      { id: player,
        score: r.branch(
                 row.eq(null),
                 points,
                 row('score').add(points))
      });
}

它具有以下行为:

> set_or_increment_score("alice", 1).run(conn)
{ inserted: 1 }
> set_or_increment_score("alice", 2).run(conn)
{ replaced: 1 }

之所以有效,是因为当文档不存在时 get returns null,并且不存在的文档上的 replace 会变成插入内容。请参阅 documentation for replace

所以我最终使用以下代码来解决无更新问题。

r.db("test").table("t").insert(
  {id:"A", type:"player", species:"warrior", score:0, xp:0, armor:0},
  {conflict: function(id, oldDoc, newDoc) {
       return newDoc.merge(oldDoc).merge(
         {armor: oldDoc("armor").add(1)});
   }
  }
)

您认为这更 readable/elegant 还是您发现代码与示例相比有任何问题?