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

时间:2019-01-19 10:20:39

标签: firebase google-cloud-firestore

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

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

这使我质疑子集合的意义是什么,如果您可以将这些文档与ID相关联的话。仅仅是在那里,以便您的文档接近1MB限制时可以扩展吗?

3 个答案:

答案 0 :(得分:4)

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

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

其中tagsquestionId对象内的子集合。现在,将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

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

  • 如果要查询数据库以获取特定问题的所有tags,则使用第一个模式非常简单,因为只需要一个CollectionReference(问题-> questionId->标记)。要使用第二个模式来实现相同的目的,需要一个CollectionReference来代替Query,这意味着您需要查询整个tags集合以仅获取对应的标签一个问题。
  • 使用第一个架构,一切都将井井有条。除此之外,在Firestore Maximum depth of subcollections: 100中。这样您就可以利用它了。
  • @RenaudTarnec在其评论中也提到,Cloud Firestore中的查询很浅,它们仅从运行查询的集合中获取文档。无法通过单个查询从顶级集合以及其他集合或子集合中获取文档。 Firestore不一次性支持跨不同集合的查询。单个查询只能使用单个集合中的文档属性。因此,您无法使用第一个架构来获取所有问题的所有标签。

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

  

它是否仅存在于其中,以便您的文档接近1MB的限制时可以扩展?

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

答案 1 :(得分:0)

我可以想到的

子集合唯一潜在的技术优势与文档大小有关-它使您可以省略对父元素的引用。 (即,对于每个相关的rootDocument -> subCollection,从根集合文档到子集合只有一个指针)。

子集合

/messages
|
 --> /messages/tags

如果tags是子集合,则它们不需要保存messageId,因为您可以通过消息文档访问标签:

collection("messages").document(messageId).collection("tags")

根集合

/messages
/tags

使用根tags集合,每个标签都需要存储messageId。基本上,这会改变指针的方向。

collection("tags").whereEqualTo("messageId", messageId)

摘要

子集合:指针来自one -> many

根集合:指针来自many -> one

答案 2 :(得分:0)

令人惊讶的是之前没有提到过,但是子集合可以(在某些情况下)帮助绕过 orderBy 限制:

<块引用>

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

假设您想获取用户最近 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);