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

问题描述 投票:1回答:1

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

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

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

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

有一个更好的方法吗?

firebase firebase-realtime-database google-cloud-firestore
1个回答
0
投票

TL;DR

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

Firestore structure with some rules

/*
  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>
}

Functions

Function A

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

  1. 查询/messages_updated获取BATCH_SIZE文档
  2. 对于每个,在本地对象中将其docId设置为true。
  3. 如果检索到BATCH_SIZE文档,则转到步骤1(还有更多内容可供读取)
  4. 对于本地对象中的每个message_key,将q / fields request_time和message_key添加到/count_likes

Function 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. 对于每个,尝试更新计数为真(并行,不原子) 如果成功,则将delta_likes增加1。
  5. 查询/likes的文档,其中message_key ==创建了docs message_key,其中delete == true,其中count == true。
  6. 对于每个doc,尝试删除它(并行,不是原子) 如果成功,则将delta_likes减1
  7. 如果delta_likes!= 0,则通过delta_likes在/messages下处理此消息的总喜欢。
  8. /count_likes删除此文档。

Function C (optional)

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

  1. /count_likes下查询request_time早于Z的文档。
  2. 对于每个文档,删除它。

On the client

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

Pros of this approach

  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的事务。这显着地减少了由于类似计数器事务导致的写入速率冲突。

Cons of this approach

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

Things to consider

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