Firestore 获取根集合的所有文档和子集合

Posted

技术标签:

【中文标题】Firestore 获取根集合的所有文档和子集合【英文标题】:Firestore get all docs and subcollections of root collection 【发布时间】:2018-04-03 05:03:54 【问题描述】:

假设我有这种结构

    A (collection):  
       a (doc): 
           name:'Tim',
           B (collection):
               b (doc): 
                      color:'blue'
               
             
          
    

其中AB集合,而ab文档。 有没有办法通过一个查询来获取根文档中包含的所有内容? 如果我这样查询

db.collection("A").doc("a").get()

我刚刚得到name:'Tim' 字段。我想要的是也得到所有B的文件。 我基本上希望我的查询返回

         
           user:'Tim',
           B (collection):
               b (doc): 
                      color:'blue'
               
             
          

是否可能或者我真的需要为每个集合进行多个查询:/?

假设我有一个代表用户配置文件的非常深的嵌套集合树,我的成本会像地狱一样增加,因为每次我加载用户配置文件时,我都有一个读取请求的乘数 1 x N 其中 N 是我的树的深度:/。

【问题讨论】:

B 是什么类型?您可以尝试一种引用类型。 引用类型最终出现同样的问题,数据没有被获取。 现在可以:firebase.googleblog.com/2019/06/… @AshClarke 没有。两者是不同的东西。 【参考方案1】:

如果您担心每次拉取的成本,则需要根据您的共同视图/拉取需求来构建数据,而不是您可能更喜欢完美的结构。如果您每次都需要将这些东西放在一起,Consider using "maps" 用于实际上不需要与文档一起作为子集合的东西。

在本例中,“首选项”是一张地图。


  user: "Tim",
  preferences: 
      color: "blue",
      nickname: "Timster"
  

每个文档的大小也限制为 1MB - 因此,如果您需要为该用户存储可以扩展并继续增长的内容,例如日志记录,那么将日志分成一个子集合是有意义的在您需要时被拉取,使每个日志条目成为一个单独的文档......并且是否所有用户的所有日志都存储在单独的父集合或每个用户的子集合中,实际上取决于您将如何提取日志和什么将导致速度快,与拉动成本相平衡。如果您要向该用户显示他们最近 10 次搜索,那么将搜索日志作为子集合会很有意义。如果您要为所有用户提取所有搜索数据以进行分析,那么单独的父级集合将是有意义的,因为您可以在 1 次拉取中提取所有日志,以防止需要分别从每个用户提取日志。

为了方便起见,您还可以将 pull 和 promise 嵌套在一起。

  // Get reference to all of the documents
  console.log("Retrieving list of documents in collection");
  let documents = collectionRef.limit(1).get()
    .then(snapshot => 
      snapshot.forEach(doc => 
        console.log("Parent Document ID: ", doc.id);

        let subCollectionDocs = collectionRef.doc(doc.id).collection("subCollection").get()
          .then(snapshot => 
            snapshot.forEach(doc => 
              console.log("Sub Document ID: ", doc.id);
            )
          ).catch(err => 
            console.log("Error getting sub-collection documents", err);
          )
      );
    ).catch(err => 
    console.log("Error getting documents", err);
  );

【讨论】:

对我来说,外部 forEach 在处理任何内部项目之前完成,因此内部项目与正确的父文档无关。输出:dropbox.com/s/2u831pue7edym2w/… 这取决于您需要对数据做什么。这里的目标是检索所有数据。如果您需要它打印出来或同步处理,您可能需要使用带有回调的计数器/递归函数一次执行一个。请记住,这将显着增加您的读/写成本。如果您只需要所有数据,那么您就拥有了一切,并且可以随心所欲地使用它。【参考方案2】:

我们知道,默认情况下,Cloud Firestore 中的查询很浅。此类查询不受支持,但 Google 可能会在未来考虑。

【讨论】:

现在支持:firebase.googleblog.com/2019/06/… @AshClarke 我浏览了这篇文章,但不明白该怎么做,您能否将其发布为答案并提及我?或引导我走向正确的方向? @AshClarke,collectionGroup 查询将跨文档查询特定名称的所有子集合,但查询仍然很浅,并且不会返回整个文档树。此外,一旦您获得了查询结果,就无法获取“拥有”文档(默认情况下)。您可以将父 docID 存储在子集合文档中并使用该值来检索父文档,但这不是自动的。【参考方案3】:

添加到 Matt R 的答案,如果你使用 babel 或者你可以使用 async/await,你可以用更少的代码得到相同的结果(没有catch/then):

// Get reference to all of the documents
console.log("Retrieving list of documents in collection");
let documents = await collectionRef.get();

documents.forEach(async doc => 
  console.log("Parent Document ID: ", doc.id);
  let subCollectionDocs = await collectionRef.doc(doc.id).collection("subCollection").get()
  subCollectionDocs.forEach(subCollectionDoc => 
    subCollectionDoc.forEach(doc => 
      console.log("Sub Document ID: ", doc.id);
    )
);

【讨论】:

以上是关于Firestore 获取根集合的所有文档和子集合的主要内容,如果未能解决你的问题,请参考以下文章

FireStore 文档如何在子集合中读取计算

如何在 Firebase + Firestore + Flutter 中使用 StreamBuilder 将所有子集合数据获取到 Widget

在 Firestore 中使用 AngularFire 列出文档的子集合

在 Firestore 中删除包含所有子集合和嵌套子集合的文档

有没有办法获取子集合中的所有文档(Firestore)

如何使用 Firebase Firestore 获取子集合? [复制]