Firestore聊天应用程序:这是用于多收件人消息的有效文档结构吗?

时间:2019-01-25 17:10:10

标签: performance firebase indexing google-cloud-firestore

假设聊天应用程序具有1000万Firebase用户和数亿条消息。

我有一个Firestore集合,其中包含以时间序列表示为文档的消息,并且这些消息中的每一个都可以被多达100个这些用户接收和查看。请注意,这些用户不是按稳定的组进行组织的,因为每条消息可能都有一组完全不同的接收消息的用户。

我需要能够非常有效地(在时间和成本方面)找到 在特定时间后将所有消息定向到特定用户。

我的第一个失败尝试是在recipients数组字段中列出收件人用户,例如:

sender: user3567381
dateTime : 2019-01-24T20:37:28Z
recipients : [user1033029, user9273842, user8293413, user6273581]

但是,那将不允许我高效地查询。

作为second failed attempt,由于Firestore是无模式的,所以我想到了使每个用户成为一个字段,如下所示:

sender: user3567381
dateTime : 2019-01-24T20:37:28Z
user1033029 : true
user9273842 : true
user8293413 : true
user6273581 : true

然后,例如,如果我想在今天3:00 PM之后知道用户8993413的所有消息,我可以这样进行:

messages.where("user8293413", "==", true).where("dateTime", ">=", "2019-01-24T15:00:00Z")

这是一个复合索引查询,每个用户需要一个索引。不幸的是,每个数据库的限制为200 composite-indexes

要解决此问题,我目前的尝试是将日期转换为用户字段的值,如下所示:

sender: user3567381
dateTime : 2019-01-24T20:37:28Z
user1033029 : 2019-01-24T20:37:28Z
user9273842 : 2019-01-24T20:37:28Z
user8293413 : 2019-01-24T20:37:28Z
user6273581 : 2019-01-24T20:37:28Z

现在,如果我想在今天3:00 PM之后知道用户8993413的所有消息,我可以这样做:

messages.where("user8293413", ">=", "2019-01-24T15:00:00Z")

请注意,这现在是 单字段索引

从文档中我知道Firestore将为所有字段创建单字段索引,因此这意味着它将为user8293413特别创建索引。 这意味着搜索将很快,对吗?并且将读取次数保持为最少(每条消息读取一次)。

但是,由于我有1000万用户,因此 Firestore必须为整个数据库创建1000万个单字段索引(假设所有用户都收到消息)。

documentation Firestore中有以下限制:

  • 数据库的最大复合索引数: 200
  • 数据库的最大单字段索引豁免数: 200
  • 每个文档的最大索引条目数: 40,000 (索引条目的数量是一个文档的以下各项的总和:单字段索引条目的数量+复合索引的数量条目)
  • 索引条目的最大大小: 7.5 KiB
  • 文档索引条目的最大大小总和: 8 MiB (总大小是文档以下各项的总和:文档单字段索引条目的大小总和+文档组合索引条目的大小总和)
  • 索引字段值的最大大小: 1500个字节(超过1500个字节的字段值将被截断。涉及截断的字段值的查询可能会返回不一致的结果。)

通过阅读以上内容,这些引起了我的注意:

  • 每个文档的最大索引条目数: 40,000
  • 文档索引条目的最大大小总和:8 MiB

但是,他们声明限制是每个文档,而不是每个数据库。而且我只有数百万个数据库索引,没有每个文档。

有问题吗?这么多索引会影响性能吗?所有这些索引的存储成本如何?是否为每个数据库中的大量索引准备了Firebase?

1 个答案:

答案 0 :(得分:0)

尽管几个月后,对于任何将来的用户来说,似乎第一次尝试都可能是最好的。

对时间戳使用单个静态字段,对收件人使用单个静态字段,则索引将保持可忽略不计,而您不必考虑它们。

要查找用户的所有消息,这似乎是您的目标:

  

例如,如果我想在之后知道用户8293413的所有消息   今天下午3:00,我可以这样做:

伪代码中,它看起来像这样:

firestore.collection('messages').where('recipient', 'array_contains', userId).where('time', '>', '3pm today'.get()

这应该在性能上足够简单,Firebase已针对其提供的运营商进行了优化,例如'==','> =','array_contains'