跟踪用户是否“喜欢”帖子

时间:2017-12-27 18:15:18

标签: firebase firebase-realtime-database google-cloud-firestore

这更像是一个理论上应该如何设置数据库,而不是编程。

假设我有一个充满卡片的新闻源,每个卡片都包含一条消息和类似的计数。每个用户都能够喜欢一个mesesage。如果他们已经喜欢该特定卡,我希望它显示给用户。 (就像你在Facebook上看到你喜欢的帖子一样,即使你几天后回来)

您将如何使用此Firestore类型数据库实现该功能?速度绝对是一个问题..

故事本地不是一个选项,我的猜测是在每个卡片对象上,你必须引用一个只保留喜欢它的人的列表的集合。唯一的问题就是更多的问题......感觉它会很慢......

有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

TL; DR

此方法需要更多设置,即cron服务,Firestore Security RulesCloud Functions for Firebase的知识。话虽如此,以下是我提出的最佳方法。请注意,只显示所需的伪规则。

具有一些规则的Firestore结构

/*
  allow read
  allow update if auth.uid == admin_uid and the
      admin is updating total_likes ... 
 */
messages/{message_key} : {
  total_likes: <int>,
  other_field:
  [,...]
}

/*allow read
  allow write if newData == {updated: true} and
      docId exists under /messages
 */
messages_updated/{message_key} : {
  updated: true
}

/*
  allow read
  allow create if auth.uid == liker_uid && !counted && !delete and
      liker_uid/message_key match those in the docId...
  allow update if auth.uid == admin_uid && the admin is
      toggling counted from false -> true ...
  allow update if auth.uid == liker_uid && the liker is
      toggling delete ...
  allow delete if auth.uid == admin_uid && delete == true and
      counted == true 
 */
likes/{liker_uid + '@' + message_key} : {
  liker_uid:,
  message_key:,
  counted: <bool>,
  delete: <bool>,
  other_field:
  [,...]
}

count_likes/{request_id}: {
  message_key:,
  request_time: <timestamp>
}

功能

功能A

每隔X分钟触发一次,以计算可能包含所有消息的消息。

  1. 查询/messages_updated了解BATCH_SIZE文档
  2. 对于每个,在本地对象中将其docId设置为true。
  3. 如果检索到BATCH_SIZE文档,则转到第1步(还有更多要阅读的内容)
  4. 对于本地对象中的每个message_key,添加到/count_likes doc w / fields request_time和message_key。
  5. 功能B

    触发onCreate of count_likes / {request_id}

    1. /messages_updated删除已创建的docs message_key。
    2. 让delta_likes = 0
    3. 查询/likes以获取文档,其中message_key ==创建了docs message_key,其中count == false。
    4. 每个
    5. ,尝试将count更新为true(并行,不是原子)
      • 如果成功,则将delta_likes增加1。
    6. 查询/likes以获取文档,其中message_key ==创建了docs message_key,其中delete == true,其中count == true。
    7. 对于每个文档,尝试删除它(并行,不是原子)
      • 如果成功,则将delta_likes减1(
    8. 如果delta_likes!= 0,则在下面处理此消息的总喜欢 delta_likes /messages
    9. /count_likes删除此文档。
    10. 功能C(可选)

      每Y分钟触发一次,删除从未遇到的/count_likes次请求。

      1. /count_likes下查询request_time早于Z。
      2. 的文档
      3. 为每个文档删除它。
      4. 在客户端

        • 查看您是否喜欢某条消息,在/likes下查询liker_uid等于您的uid的文档,其中message_key等于消息的密钥,其中delete == false。如果存在doc,你就喜欢它了。
        • /likes和batch.set a /messages_updated下添加消息,批量设置。如果此批处理失败,请尝试使用batch_two.update,方法是将其delete字段更新为false,并将batch_two.set更新为/messages_updated
        • 与邮件不同,通过将其删除字段更新为true并批量设置为/messages_updated来批量更新。

        这种方法的优点

        1. 这可以扩展到其他东西的计数器,而不仅仅是消息。
        2. 用户可以看到他们是否喜欢某些内容。
        3. 用户只能喜欢一次。
        4. 用户可以通过垃圾邮件切换类似按钮,这仍然有效。
        5. 任何用户都可以通过message_key查询/likes来查看哪些人喜欢哪条消息。
        6. 任何用户都可以通过liker_uid查询/likes来查看用户喜欢的所有邮件。
        7. 只有云计算管理员会更新您的计数。
        8. 如果为同一事件多次触发一个函数,则此函数是安全的,这意味着对于相同的情况,计数不会多次递增。
        9. 如果某个事件未触发某个函数,则此方法仍然有效。这只是意味着在下次其他人喜欢相同的消息时,计数才会更新。
        10. 喜欢被非规范化为一个根级别集合,而不是如果您在消息“喜欢子集合”下并且在liker的messages_liked子集合下具有类似性的那两个集合。
        11. 每个消息的计数都是批量更新的,即如果已经被喜欢了100次,则只需要100个100的事务,而不是100个100的事务。这会减少由于类似计数器事务而导致的写入速率冲突。
        12. 这种方法的缺点

          1. 计数只会更新,但是你的cron工作经常会被解雇。
          2. 依靠cron服务来解决,一般来说还有更多设置。
          3. 要求该函数使用有限权限进行身份验证,以在/likes下执行安全写入。在实时数据库中,这是possible。在Firestore中,它是可能的,但有点hacky。如果您可以等待并且不想使用hacky方法,请在开发中使用常规无限制管理员,直到Firestore支持使用有限权限进行身份验证。
          4. 根据您的观点,可能会很昂贵。您应该考虑函数调用和读/写计数。
          5. 需要考虑的事项

            1. 当您在功能B中处理计数时,如果超过1 /秒的最大写入速率并且事务失败,您可能需要考虑多次尝试。
            2. 在功能B中,如果您希望每个消息计算很多喜欢,您可能希望实现类似于功能A的批量读取。
            3. 如果您需要定期更新消息(在另一个cron作业中),您可能需要考虑将该功能合并到功能B中,因此不会超过1 /秒的写入速率。