访问集合组查询中每个DocumentReference的父数据

问题描述 投票:0回答:4

我有一个companies的集合,并且在每个公司文档中,我都有一个appointments的集合。我想在一个云函数中遍历所有appointments的所有companies,因此我正在使用以下收集组查询:

db.collectionGroup('appointments')
    .get()
    .then((querySnapshot: any) => {
        querySnapshot.forEach((appointmentDoc: any) => {
            const appointment: Appointment = appointmentDoc.data();
            appointmentDoc.ref.parent.parent.get().then((companyDoc: any) => {
                const company: Company = companyDoc.data();
                ...
            });
        });
     });

您可以看到,在每次迭代中,我也都获得了约会来自的公司的数据。这可行,但是我担心性能。如果我有500个约会,那么此方法基本上不是对数据库进行501调用(对约会进行1次调用,然后获取所有500个约会的公司数据)吗?有没有一种更好的方法可以访问该父数据,所以我不会进行所有这些额外的调用?如果我可以按比例扩展此方法,那就太好了。

javascript firebase google-cloud-firestore
4个回答
1
投票

无法与appointments集合中的文档同时获取父文档。

您唯一可以做的是将文档ID分成10组,然后对它们进行IN query。但是我怀疑是否值得付出努力,因为电汇流量可能几乎相同。

请注意,尽管性能通常与通话次数没有线性关系,所以请在进行优化之前进行测试。另请参阅IN

也:请考虑一下为什么一次需要500个文档。通常,您将需要加载筛选的数据,这似乎要多得多。有关Firestore中数据建模的一般提示,我推荐Google Firestore - how to get document by multiple ids in one round trip?的第一集。


1
投票

Firestore实际上不会根据查询数向您收费。它基于文档读取次数。因此,如果您有500个约会,那么您的代码将读取1000个文档,因为它为每个约会文档读取一次公司文档。

您可以做的只是只读取一次每个公司文档total,而不是一次针对该公司的每次约会。您可以使用以下方法在内存中维护高速缓存:

Getting to know Cloud Firestore

尽管这是不完整的,因为内部查询仍然是异步的,并且将继续以约会迭代器可以运行的速度查询公司。您将必须以某种方式对内部查询进行序列化,或者按公司ID对约会进行分组,然后对这些组进行迭代,以免多次获取公司文档。

但是我希望您在这里有了一个想法,即使用内存缓存可以节省您的文档读取。


0
投票

我使用了非常分层的结构,看起来会遇到类似的问题,但是...

...对于像Firestore这样的NoSQL数据库,您必须放弃DRY的SQL要求。如果数据是静态的(例如,您实际需要进行约会的任何“公司”数据),则您绝对可以并且应该复制该数据。

例如,您可以将结构简单地添加到附件文档中:

// cache of companies identified by their document ID
const companies: { [key: string]: Company } = {}

db.collectionGroup('appointments')
    .get()
    .then((querySnapshot: any) => {
        querySnapshot.forEach((appointmentDoc: any) => {
            const appointment: Appointment = appointmentDoc.data();
            const parentRef = appointmentDoc.ref.parent.parent
            const companyId = parentRef.id
            let company: Company
            if (companies[companyId]) {
                company = companies[companyId]
                // work with cached company here
            }
            else {
                parentRef.get().then((companyDoc: any) => {
                    company: Company = companyDoc.data();
                    companies[companyId] = company
                    // work with queried company here
                });
            }
        });
     });

是的,这使用存储空间。所以? Firestore通常不收取少量的额外存储费用,并且收取新副本的费用[[does。由于此数据不会动态更改,因此在创建约会文档时将其添加到约会文档中效率更高。

应该为动态数据保留文档提取。

0
投票
另一点:文档的refPath是一个字符串,代表到文件的完全限定的'/'分隔路径:

appointmentSchema = { .... .... company: { id: {string}, name: {string}, location: {string} } }

...,您可以直接解析此字符串以在文档路径的任何地方

up查找集合名称和documentId。我也经常使用它。

© www.soinside.com 2019 - 2024. All rights reserved.