【问题标题】:Firestore - deep collection query in one loopFirestore - 一个循环中的深度集合查询
【发布时间】:2020-10-09 16:22:41
【问题描述】:

我有一个像这样的 firestore 对象:

{
  countries:[
    country1: {
      cities: [
        city1: {date_added: timestamp},
        ...
      ]
    }
    ...
  ]
}

所以我希望在一个查询中 获得城市列表。我知道我可以去(我在 Firestore 功能中)

const cities = [];

admin.firestore().collection('countries/')
    .get()
    .then(countriesSnapshot => {
      countriesSnapshot .forEach( countryDoc => {
        admin.firestore().collection('countries/' + countryDoc.id + '/cities/')
          .get()
          .then(citySnapshot => {
            citySnapshot.forEach( cityDoc => {
              cities.push(cityDoc.id);
            });
          }).catch();
      });
    }).catch();

但这会进行双重 foreach,我只想在一切都解决后进行处理。我可以使用promise.all,但我想知道是否有更简单的方法——比如

admin.firestore().collection('countries/{countryId}/cities').get().then(citySnapshot ...

【问题讨论】:

    标签: node.js firebase google-cloud-firestore google-cloud-functions firebase-admin


    【解决方案1】:

    因此,看起来不可能在特定的子集合中发生这种情况 = Frank 的回答提供了一个解决方案,该解决方案在某些情况下可能有效,但不适用于我的解决方案,因为我的名字在我的数据库中不是唯一的。

    所以我的解决方案是让它在两个循环中发生,但不是一个循环到另一个循环 - 使用 Promises。像这样:

    admin.firestore().collection('countries/')
      .get()
      .then(countriesSnapshot => {
        const citiesPromises = [];
        countriesSnapshot.forEach( countryDoc => {
          citiesPromises.push(admin.firestore().collection('countries/' + countryDoc.id + '/cities/').get());
        });
        Promise.all(citiesPromises).then(resources => {
          for (const resource of resources) {
            resource.forEach( doc => {
              // do stuff with doc.id or doc.data()
            });
          }
        }).catch();
      }).catch();
    

    【讨论】:

      【解决方案2】:

      如果要查询所有cities 集合,可以使用collection group query

      let cities = db.collectionGroup('cities');
      cities.get().then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
          console.log(doc.id, ' => ', doc.data());
        });
      });
      

      这将返回所有国家/地区的所有城市。

      【讨论】:

      • 很好,但是如果我在一个我不想包含的地方有另一个名为 city 的集合,它也会出现。例如,如果可以let cities = db.collectionGroup('cities', '/countries');,那就太好了,所以它只会寻找cities 子集合。
      • 不幸的是,集合组查询目前是全局基于名称的,不能基于路径(相信我:我真的也希望看到这些)。因此,此方法要求您为集合类型提供唯一名称,例如 country_cities。我还经常发现自己不得不将数据从乡村复制到城市。与 NoSQL 数据库一样:我们必须修改数据模型以适应应用程序的用例。
      • 是的,我不得不去规范化,这很正常 :) 但在这里我正在为一个已经在生产中的应用程序编写脚本......哦,我想我会写一个预脚本来复制我想要的数据。谢谢
      猜你喜欢
      • 1970-01-01
      • 2018-12-31
      • 1970-01-01
      • 2021-06-10
      • 2018-03-18
      • 2019-12-03
      • 1970-01-01
      • 1970-01-01
      • 2020-11-21
      相关资源
      最近更新 更多