【问题标题】:How to atomically update a document in RethinkDB based on old value?如何根据旧值自动更新 RethinkDB 中的文档?
【发布时间】:2020-04-29 16:47:30
【问题描述】:

假设我有一个如下的文档架构:

{
  users: [{userid: 123, username: "foo"}, {userid: 234, username: "bar"}]
}

我想向users 添加一个用户名等于给定用户名的“唯一”版本的项目。例如,如果我尝试将{userid: 456, username: "baz"} 添加到上面的用户列表中,它应该会成功,但是如果我尝试将{userid: 456, username: "foo"} 添加到上面,那么应该添加{userid: 456, username: "foo (1)"}

有没有办法通过 RethinkDB 中的原子更新来做到这一点?这是一个确定性操作,所以理论上应该是可能的吧?如果没有,是否有某种方法可以至少在插入期间检测到用户名冲突并简单地拒绝更新?

我知道我可以使用子查询,但结果似乎不是原子操作?我在文档中看到的所有子查询示例都在单独的表中显示子查询。

【问题讨论】:

    标签: nosql rethinkdb


    【解决方案1】:

    根据consistency guarantees,您可以将get(不是getAllfilter)与update 组合起来,并拥有一个原子链。然后,在update 内部,described 表示,如果您使用子查询或不确定的东西,那么您就不是原子的,必须显式声明 nonAtomic 标志。

    查询中最冗长的部分变成了增加计数的方法,因为您不想以多个 bar (1) 结尾。

    假设您已经提供了以下内容,则应该是原子行为:

    • 文档的id,这里是did = '3a297bc8-9fda-4c57-8bcf-510f51158f7f'
    • 用户名,这里是uname = 'bar'
    • 用户ID,这里是uid = 345
    var uname = 'baz';
    var did = "3a297bc8-9fda-4c57-8bcf-510f51158f7f";
    var uid = 345;
    // not sure readMode is necessary here, it's described in consistency guarantees
    //  but not shown in the example with get/update/branch
    r.db('db').table('table', { readMode: 'majority' })
    // use only get to ensure atomicity between get and update
    .get(did)
    // update will throw if you're not deterministic, i.e. it can't behave atomically
    //  here we never address anything but the current document so it's OK
    .update(function(doc) {
      // this retrieves the highest index in parentheses if any
      //  put in a var because 1/ we use the result twice 2/ it's kind of verbose...
      var matched = doc('users').map(function(user) {
        // regex is /^bar(?: \(([0-9]+)\))?$/
        //  with the only capturing group on the index itself
        return user('username').match(r.expr('').add('^', uname, '(?: \\(([0-9]+)\\))?$'))
      }).filter(function(match) {
        // remove all user items that didn't match (i.e. they're null)
        return match.typeOf().ne('NULL');
      }).map(function(match) {
        // check whether we are processing 'bar' or 'bar (N)'
        //  (no captured group = no '(N)' = pure 'bar' = set index at zero)
        return r.branch(
          match('groups').filter(function(group) {
            return group.typeOf().ne('NULL');
          }).count().gt(0),
          // wrap in { index } for the following orderBy
          { index: match('groups').nth(0)('str').coerceTo('number') },
          { index: 0 }
        );
      })
      // ensure the first item in the list is the highest index
      .orderBy(r.desc('index'));
      // now we can decide on what to add
      return r.branch(
        // if there were some matches, 'bar' exists already
        //  and we now have the highest index in the list
        matched.count().gt(0),
        // add 'bar' appended with ' (N)', having N = highest index + 1
        {
          users: doc('users').add([{
            userid: uid,
            username: r.expr(uname).add(
              ' (',
              matched.nth(0)('index').add(1).coerceTo('string'),
              ')'
            )
          }])
        },
        // else, just add the user as is
        { users: doc('users').add([{ userid: uid, username: uname }]) }
      );
    });
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多