Доступ к родительским данным для каждого DocumentReference в запросе группы сбора - PullRequest
0 голосов
/ 24 марта 2020

У меня есть коллекция companies, и внутри каждого документа компании у меня есть коллекция appointments. Я хочу l oop через все 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 встреч)? Есть ли лучший способ получить доступ к этим родительским данным, чтобы я не делал все эти дополнительные вызовы? Было бы здорово, если бы я мог сделать это таким образом, чтобы масштабировать.

Ответы [ 4 ]

1 голос
/ 24 марта 2020

Firestore фактически не выставляет вам счет на основании количества запросов. Он основан на количестве прочитанных документов. Итак, если у вас 500 встреч, ваш код будет читать 1000 документов, поскольку он читает документ компании один раз для каждого документа встречи.

Вместо этого вы можете читать только один документ компании только один раз всего , не один раз за каждое назначение для этой компании . Для этого можно сохранить кэш в памяти, используя что-то вроде этого:

// 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
                });
            }
        });
     });

Хотя это неполно, потому что внутренний запрос все еще асинхронный и будет продолжать запрашивать компании так быстро, как может выполняться итератор назначения. , Вам нужно будет как-то сериализовать внутренний запрос или сгруппировать встречи по идентификатору компании и выполнить итерации групп, чтобы вы не могли получить документ компании более одного раза.

Но я надеюсь, что вы поняли, что здесь Использование кеша памяти может сохранить ваши чтения документа.

1 голос
/ 24 марта 2020

Я использую очень иерархическую структуру, которая выглядела бы так, как будто бы у нее были похожие проблемы, НО ...

... с базой данных SQL, такой как Firestore, вы должны УДАЛИТЬ SQL мантра DRY. Если данные имеют статус c (например, какие бы данные «компании» вам на самом деле не требовались для назначения), вы можете и должны копировать эти данные.

Например, вы может довольно просто добавить к документу о встрече структуру:

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

Да, это использует хранилище. Так? Firestore в основном не взимает плату за этот небольшой объем дополнительного хранилища, а взимает плату за получение новой копии. Поскольку эти данные не изменяются динамически, гораздо эффективнее добавить их в документ встречи при создании.

выборка документа должна быть зарезервирована для динамических c данных.

1 голос
/ 24 марта 2020

Невозможно получить родительские документы одновременно с документами из коллекции appointments.

Единственное, что вы можете сделать, это собрать идентификаторы документов в пакеты по 10, а затем выполнить IN запрос с ними. Но я сомневаюсь, что оно того стоит, потому что трафик c, скорее всего, почти такой же.

Обратите внимание, что производительность обычно не коррелирует линейно с количеством вызовов, поэтому проверьте, прежде чем пытаться оптимизировать его. , Также см. Google Firestore - как получить документ по нескольким идентификаторам за одну поездку? .

Также: подумайте, зачем вам нужно 500 документов одновременно. Как правило, вы хотите загрузить скриншот данных, и это, кажется, намного больше. Для общих советов о моделировании данных в Firestore, я рекомендую первый набор эпизодов Знакомство с Cloud Firestore .

0 голосов
/ 24 марта 2020

Еще один момент: refPath документа - это строка, представляющая полный путь к документу, разделенный '/':

root/topcollection/topdocumentId/nextcollection/nextdocumentId/bottomcollection/bottomdocumentId

... и вы можете напрямую проанализировать эту строку, чтобы найти коллекцию Имена и documentId в любом месте до путь к документу. Я тоже немного этим пользуюсь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...