当前位置: 首页 > 知识库问答 >
问题:

在firestore中使用子集合有什么好处吗?

云凌
2023-03-14

我为我的应用的用户集合中的每个文档都有一个子集合。此子集合存储与用户相关的文档,但是它们也可以保存到主集合中,每个文档都有一个关联的 userId。

我选择了这种结构,因为它在当时似乎是最明显的,但我可以想象,如果我需要进行数据库维护,它将使事情变得更加困难。例如,如果我想清理这些文档,我必须先查询每个用户,然后再查询每个用户的文档,而如果我有一个主集合,我可以只查询所有文档。

这让我不禁要问,如果可以将这些文档与一个ID关联起来,那么子集合到底有什么意义呢?如果你的文档接近1MB的限制,你可以扩展它吗?

共有3个答案

郑伟彦
2023-03-14

很惊讶这之前没有提到过,但子集合可以(在某些情况下)帮助绕过订单通过限制:

不能按等式 (==) 或子句中包含的字段对查询进行排序。

假设您要获取用户最近 10 次登录:

顶级:

//We can't use .orderBy after .where('==')
USER_LOGINS.where('userId', '==', {uid}).limit(10) 

子集合:

//With a subcollection we can order and limit properly
USERS.doc({uid}).collection('LOGINS').orderBy('unixCreated', 'desc').limit(10);
薛华容
2023-03-14

我发现子集合的一个最大优点是它们有自己的写速率限制,因为每个子集合都有自己的索引(假设没有集合组索引)。对于小型应用程序来说,这可能不是一个问题,但是对于中型/大型应用程序来说,这可能非常重要。

想象一个聊天应用程序,其中每个聊天都有一系列消息。您需要按时间戳为邮件编制索引,以便按时间顺序显示邮件。顺序值的 Firestore 写入限制为 500/秒,这绝对是中型应用所能达到的(特别是如果您考虑恶意用户编写脚本消息的可能性 - 目前使用安全规则不容易防止)

// root collection

/messages {
  chatId: string
  timeSent: timestamp // the entire app would be limited to 500/second
}
// sub-collection

/chat/{chatId}/messages {
  timeSent: timestamp // each chat could safely write up to 500/second
}
百里芷阳
2023-03-14

编辑: 2021年10月29日:

要明确文档中存在的以下句子:

如果您不根据具有顺序值的字段进行查询。

时间戳不能被视为连续的。但是,它仍然可以被认为是连续的。同样的规则也适用于按字母顺序(Customer1,Customer2,Customer3,...),或者几乎所有可以被视为可预测生成价值的东西。

Firestore索引中的这种顺序数据最有可能被写入存储介质上的物理邻近区域,因此存在这种限制。

话虽如此,请注意Firestore使用一种机制将文档映射到相应的位置。这意味着,如果值不是随机分布的,则写入操作将不会正确分布在各个位置上。这就是这种限制存在的原因。

另请注意,您在特定时间内可以向此类位置写入多少数据是有物理限制的。可预测的键/值很可能最终会出现在同一个位置,这实际上是不好的。因此需要进行更多更改才能达到限制。

编辑:2021年7月16日:

由于这个答案听起来有点老套,我将尝试添加使用随时间推移发现的子集合的更多优点:

  1. 子集合将始终为您提供更结构化的数据库模式,因为您始终可以引用仅与特定文档相关的子集合。因此,您只能嵌套与特定文档相关的数据。
  2. 如前所述,子集合的最大深度为100。因此,这里的一个重要特性是FirestQuery在级别1时的速度与在级别100时一样快。因此不应该担心深度。此功能已测试。
  3. 默认情况下,子集合中的查询会被索引,就像顶级集合一样。
  4. 在速度方面,查询顶级集合、子集合或集合组并不重要,速度总是相同的,只要查询返回相同数量的文档。发生这种情况是因为查询性能取决于您请求的文档数量,而不是搜索的文档数量。因此查询子集合与查询顶级集合具有相同的效果,完全没有缺点。
  5. 在子集合中存储文档时,请注意无需将文档ID存储为字段,因为默认情况下它是引用的一部分。这意味着您可以在子集合中存在的文档中存储更少的数据。更重要的是,如果您将相同的数据保存在顶级集合中,并且您需要创建一个Query,其中EqualTo()调用orderBy()调用,则需要索引。
  6. 在安全性方面,子集合允许继承安全规则,这很有用,因为我们可以编写越来越少的代码来保护数据库。

就目前而言,如果我发现了其他好处,我会更新答案。

让我们举一个例子。让我们假设我们有一个测验应用程序的数据库模式,如下所示:

Firestore-root
    |
    --- questions (collections)
          |
          --- questionId (document)
                 |
                 --- questionId: "LongQuestionIdOne"
                 |
                 --- title: "Question Title"
                 |
                 --- tags (collections)
                      |
                      --- tagIdOne (document)
                      |     |
                      |     --- tagId: "yR8iLzdBdylFkSzg1k4K"
                      |     |
                      |     --- tagName: "History"
                      |     |
                      |     --- //Other tag properties
                      |
                      --- tagIdTwo (document)
                            |
                            --- tagId: "tUjKPoq2dylFkSzg9cFg"
                            |
                            --- tagName: "Geography"
                            |
                            --- //Other tag properties

其中< code>tags是< code>questionId对象中的子集合。现在,让我们将< code>tags集合创建为顶级集合,如下所示:

Firestore-root
    |
    --- questions (collections)
    |     |
    |     --- questionId (document)
    |            |
    |            --- questionId: "LongQuestionIdOne"
    |            |
    |            --- title: "Question Title"
    |
    --- tags (collections)
          |
          --- tagIdOne (document)
          |     |
          |     --- tagId: "yR8iLzdBdylFkSzg1k4K"
          |     |
          |     --- tagName: "History"
          |     |
          |     --- questionId: "LongQuestionIdOne"
          |     |
          |     --- //Other tag properties
          |
          --- tagIdTwo (document)
                |
                --- tagId: "tUjKPoq2dylFkSzg9cFg"
                |
                --- tagName: "Geography"
                |
                --- questionId: "LongQuestionIdTwo"
                |
                --- //Other tag properties

这两种方法之间的区别是:

  • 如果您想查询数据库以获取特定问题的所有标记,使用第一个模式非常简单,因为只需要集合引用(问题-

这种技术称为数据库扁平化,在Firebase中是一种非常常见的做法。因此,仅在需要时使用此技术。因此,在您的情况下,如果您只需要显示单个问题的标签,请使用第一个模式。如果您想以某种方式显示所有问题的所有标签,建议使用第二个模式。

如果你的文档接近1MB的限制,你可以扩展它吗?

如果文档中有对象的子集合,请注意,该子集合的大小不计入1 MiB限制。仅计算存储在文档属性中的数据。

编辑2019年10月1日:

根据@ShahoodulHassan的评论:

因此,您无法使用第一个架构获取所有问题的所有标记?

实际上,现在有了,我们可以使用Firestore集合组查询获得所有问题的所有标签。需要注意的一点是,所有子集合必须具有相同的名称,例如标记

 类似资料:
  • 问题内容: 我的应用程序中有一些内存泄漏。它们都起源于一个特定的视图集群,我花了大量时间进行调整,并尝试减少尽可能多的上下文传递。这使我相信群集中使用的位图就是问题所在。因此,我考虑将WeakReferences用于所有对视图使用的位图的引用。我从未使用过WeakReference,并且不确定这是否是一个好的应用程序。任何机构都可以提供有用的指示或技巧吗? 问题答案: 因此,我考虑将WeakRef

  • 我正在尝试为firestore中的社交媒体应用程序组织数据。为帖子创建一个新集合或将其放入用户的子集合更好吗? 深度应该是一样的,但是一种方式比另一种方式有什么优势吗? 创建新集合: 职位(集合) 用户(集合) 用户中的子集合: 用户(集合)

  • 本文向大家介绍使用黄瓜有什么好处?,包括了使用黄瓜有什么好处?的使用技巧和注意事项,需要的朋友参考一下 下面列出了使用黄瓜的一些优点- Cucumber是一种开源工具,不需要许可。 黄瓜可以通过Eclipse等IDE轻松配置。 黄瓜弥合了开发人员,测试人员,业务分析师,客户和产品所有者之间的理解和沟通差距。 黄瓜使没有技术知识的业务利益相关者参与其中。 黄瓜提供纯文本表示形式,使团队中的非技术人员

  • 问题内容: 我正在浏览以下代码示例: 我想知道使用Iterator接口的实现而不是使用普通的for-each循环有什么好处? 如果此示例不相关,那么当我们应该使用Iterator时会是一个好的情况吗? 谢谢。 问题答案: 该 for-each循环 与Java 5中引入的,所以它不是那么“老”。 如果只想迭代一个集合,则应为每个循环使用 但是有时“普通的” 迭代器的 方法对于检查 迭代器 是否还有更

  • 问题内容: 我只是想知道什么是确定的利益/用途 用于在数据类型? 问题答案: 选择带有类型的列时,它将用零填充字段的显示值,直到字段定义中指定的显示宽度。大于显示宽度的值不会被截断。请注意,的使用还意味着。 使用和显示宽度不会影响数据的存储方式。它仅影响其显示方式。 以下是一些示例SQL演示了如何使用: 结果:

  • 我的FiRecovery数据库中有一个名为Reports的集合,我已经在其中添加了文档。但我现在的问题是我想在报表中添加一个带有子集合的文档,有什么想法吗?