在Firebase中正确设计主演/喜欢系统:我应该使用交易吗?

Lyl*_*yla 6 android transactions firebase firebase-realtime-database

我正在开发一个应用程序,它在Firebase文档中给出的博客文章示例中执行与星数类似的操作,我对轮询系统的设计以及是否使用有疑问.

从示例中,帖子的数据如下所示:

postid {
    // some data here about the post, author, id, etc,
    starCount : <an integer count of the stars>,
    stars : {
        <user who starred> : true,
        <user who starred> : true,
        // ... and so on, basically a list of all the users who starred the post
    }
}
Run Code Online (Sandbox Code Playgroud)

文档使用事务来更新星号:

private void onStarClicked(DatabaseReference postRef) {
    postRef.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(MutableData mutableData) {
            Post p = mutableData.getValue(Post.class);
            if (p == null) {
                return Transaction.success(mutableData);
            }

            if (p.stars.containsKey(getUid())) {
                // Unstar the post and remove self from stars
                p.starCount = p.starCount - 1;
                p.stars.remove(getUid());
            } else {
                // Star the post and add self to stars
                p.starCount = p.starCount + 1;
                p.stars.put(getUid(), true);
            }

            // Set value and report transaction success
            mutableData.setValue(p);
            return Transaction.success(mutableData);
        }

        @Override
        public void onComplete(DatabaseError databaseError, boolean b,
                               DataSnapshot dataSnapshot) {
            // Transaction completed
            Log.d(TAG, "postTransaction:onComplete:" + databaseError);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

因为采用了交易的双方starCount,并stars似乎需要是同一对象的一部分.为什么?因为我想同时使用交易并确保自动化.确保自动性的另一个选项是多路径更新,但是如注释中所述,您不能使用带有转换的多路径更新.您可以访问mutableData(在这种情况下是post对象),就是这样.

所以如果starCount并且stars必须存储在同一个位置,我不明白starCount的要点.每当你得到一个帖子对象时,它都会包含stars所有出演它的人的列表.为什么不完全删除starCount并获得星星列表的大小?这有什么不高效的吗?

在这种情况下,主演/取消明星的东西就像p.stars.put(getUid(), true);p.stars.remove(getUid());.如果我这样做,我认为不需要交易,因为我不再有多个用户更新"计数器"对象.我可以在p.stars.put(getUid(), true);声明中使用一个事务,但对我来说,尝试在两个不同的设备上播放/解除某些内容的同一个用户似乎不太可能,即使他们这样做了,就我所知,这不会是灾难性的.

那我在这里错过了什么?为什么在这里使用交易以及存储和手动跟踪starCount会增加哪些好处?我可以看到将stars用户列表存储在数据库中其他位置的性能优势,如此示例所示,但随后事务将无法工作.

任何见解将不胜感激,谢谢!

Fra*_*len 1

在我们努力创建一个可从中获取文档示例的工作示例应用程序时,我们确实可能创建了一种不合理(但功能性)的交易用途。

我建议查看我对这个问题的回答,以获得使用多位置更新和服务器端安全规则进行安全计数的更合理(但绝对复杂)的方法。

但总的来说,在这种情况下,我总是建议将投票逻辑与计数逻辑分开。因此,当用户对帖子投票时,您可以在数据库中写入一条简单的记录来记录他们的操作:

votesQueue
   <push id>
      <uid>: true
Run Code Online (Sandbox Code Playgroud)

然后你有一个小型服务器脚本(例如firebase 队列工作程序)来侦听该队列并聚合投票数。

这种方法在使用 Firebase 时非常常见,并且使事情变得简单得多。您可能很容易想象如何保护这两个节点(votesQueuevoteTotals),而我可以向您保证,我上面链接的答案中的解决方案给我带来了相当大的维护麻烦。