Firebase - 实时数据库中 2 条路径的一个事务

Firebase - One transaction for 2 paths in real time database

我有一个具有以下结构的数据库:

现在可以对两幅画进行评分,然后更新评分。 但是可能会发生一幅画同时被多次评级的情况。因此我尝试使用嵌套事务(见下文)来避免竞争条件:

function pictureClicked(picture) {
    const db = getDatabase();
    const leftRef = ref(db, '/paintings/' + generateDbName(currentLeft));
    const rightRef = ref(db, '/paintings/' + generateDbName(currentRight));
    const winnerLeft = (picture === 'left') ? 1 : 0;

    runTransaction(leftRef, (leftP) => {
        if (leftP) {
            runTransaction(rightRef, (rightP) => {
                if (rightP) {
                    // Calculation of the new rating for each painting (Elo System)
                    const tRatingLeft = Math.pow(10, leftP.rating / 400);
                    const tRatingRight = Math.pow(10, rightP.rating / 400);

                    const expectedLeft = tRatingLeft / (tRatingLeft + tRatingRight);
                    const expectedRight = tRatingRight / (tRatingLeft + tRatingRight);

                    // Setting new rating
                    leftP.rating = leftP.rating + 32 * (winnerLeft - expectedLeft);
                    rightP.rating = rightP.rating + 32 * ((1 - winnerLeft) - expectedRight);
                }
                return rightP;
            });
        }
        return leftP;
    });
}

现在这个解决方案并没有真正奏效,而且我读到它不是解决这个问题的最佳方法。我找到的唯一解决方案是 运行 我数据库根目录上的事务,但我担心这会导致瓶颈,许多已启动的事务甚至不会写入数据库,因为事务只会重试25 次(或者我的担心是没有根据的?)。这个问题还有其他解决方案吗?

Firebase 实时数据库事务 运行 针对数据库中的单个路径。目前没有办法 运行 针对多路径的事务,因此常见的方法是 运行 针对最低级别共享路径的事务(在您的情况下为 /paintings)。

这确实会导致更多争用,因为您有更多用户执行并发事务。


我有时使用的唯一替代方法是使用以下方法构建我自己的交易机制:

  1. 多路径更新,同时执行两个写入。
  2. 安全规则,只允许在我的用例中有意义的转换。
  3. 客户端重试,以便仍能正确处理争用或过时的数据。

即使对于简单的情况,这也是相当重要的,并且可能需要更改您的数据结构 and/or 为每个请求添加额外的值。但是,如果您克服了这些障碍,它将允许您 运行 跨多个路径进行“交易”。