代码之家  ›  专栏  ›  技术社区  ›  Marcelo Glasberg

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

  •  3
  • Marcelo Glasberg  · 技术社区  · 6 年前

    假设一个聊天应用有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之后用户8293413的所有消息,我可以这样做:

    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点之后用户8293413的所有消息,我可以这样做:

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

    请注意,这是一个 单字段索引 .

    从文档中,我知道Firestore将为所有字段创建单字段索引,因此这意味着它将为特定的用户8293413创建索引。 这意味着搜索会很快,对吗?并且读取次数将保持在最低限度(每条消息读取一次)。

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

    documentation Firestore有以下限制:

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

    通过阅读以上内容,我注意到:

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

    然而,他们表示,限制是有限的 对于每个文档 ,而不是每个数据库。我只有数百万个数据库索引,而不是每个文档。

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

    0 回复  |  直到 6 年前
        1
  •  0
  •   Thingamajig    5 年前

    虽然几个月后,对于任何未来的用户来说,第一次尝试似乎效果最好。

    使用一个静态字段作为时间戳,使用一个静态字段作为收件人,这意味着索引仍然可以忽略不计,您不必考虑它们。

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

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

    这看起来就像这样 伪码 :

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

    这在性能上应该足够简单,Firebase针对其提供的运算符进行了优化,例如“==”、“>='、”等数组_包含'