首页 > 解决方案 > 如何更新事务中的多个节点(Firebase 实时数据库)

问题描述

对于以下数据库示例结构:

  {
    "stats": {
      "posts_count": 231,
      "posts_by_category": {
        "sports": {
          "count": 12,
          "foo": "bar"
        }
      },
      "posts_by_language": {
        "english": {
          "count": 12,
          "foo": "bar"
        }
      }
    }
  }

并且给定 [english, sports] 类别中的新帖子,我如何运行具有以下更改的事务:

stats/posts_count +1
stats/posts_by_category/sports/count +1
stats/posts_by_language/english/count +1

基本上我不知道如何导航/编辑 MutableData 对象以反映更改,我想要一个示例(最好不使用 DAO 类)

db.getReference("stats").runTransaction(object : Transaction.Handler {
    override fun doTransaction(currentData: MutableData): Transaction.Result {
        ????
        return Transaction.success(currentData)
    }

    override fun onComplete(
        error: DatabaseError?,
        committed: Boolean,
        currentData: DataSnapshot?
    ) {
    }
})

标签: androidfirebasekotlinfirebase-realtime-database

解决方案


事务在单个节点上运行。因此,如果您想以事务方式更新数据库中的多个分支,则必须在最低的公共祖先节点上运行单个事务。在你的例子中是stats. 请注意,这可能会在写操作上产生很多争用。如果stats节点可能在同一时间被许多客户端更新,这可能会导致多次重试并可能导致事务失败。

不过,在您的示例中,您似乎想要增加计数器,Firebase 实时数据库自今年早些时候以来将其作为本机操作支持。stats因此,我不会在 上运行事务,而是对其运行以下更新操作:

Map<String, Object> updates = new HashMap<>();
updates.put("posts_count", ServerValue.increment(1));
updates.put("posts_by_category/sports/count", ServerValue.increment(1));
updates.put("posts_by_language/english/count", ServerValue.increment(1));
db.getReference("stats").updateChildren(updates);

这里需要注意的事项:

  • 这里/的键是一个特殊的符号,允许更新嵌套的属性。
  • ServerValue.increment(1)作为标记发送到数据库,然后由数据库自动执行。

推荐阅读