Получить вложенную коллекцию из firestore из того же объекта — React typescript

#firebase #google-cloud-firestore #react-typescript

#firebase #google-облако-firestore #реагировать-машинопись

Вопрос:

Мой интерфейс выглядит так:

Интерфейс реагирует:

 export interface UserTask {
    assignee: String;
    date: String;
}


export interface TaskData {
    id: String;
    taskName: string;
    taskIcon: string;
    taskLog: UserTask[] 
}
 

Модель данных Firebase (структура):

Скриншот Firebase

 - taskData (Main Collection)
    - taskIcon (fields)
    - taskName (fields)
    - taskLog (sub-collection) 
        - assignee  (fields)
        - date (fields)
 

Реагировать на код для получения данных firestore:

 import { firestore } from '../firebase';
 

 function toTaskData(doc): TaskData {
    if (!doc.exists) {
        throw new Error("TaskData  not found!");
    } else {

        return { id: doc.id, ...doc.data()  } as TaskData;
    }
  }


  const getTaskData = async() => {
    const taskDataRef = firestore.collection('taskData');
    await taskDataRef.get().then(({docs}) => {
      setTaskData(docs.map(toTaskData));
    });
  }
 

Ответ JSON из firestore:

введите описание изображения здесь

Я получаю только ответ, который содержит массив taskName и taskIcon , а не вложенную taskLog коллекцию, мой вопрос в том, как мне получить вложенную коллекцию или сопоставить ее с массивом пользовательских задач?

Ответ №1:

Запросы Firestore являются мелкими: когда вы извлекаете документ, вы не извлекаете данные, содержащиеся ни в одной из связанных с ним вложенных коллекций.

Если вы хотите получить документ Firestore вместе со всеми документами из одной из его вложенных коллекций, вам нужно выполнить две выборки: одну выборку для «родительского» документа и одну для всех документов вложенной коллекции.

Например, вы можете сделать что-то в следующих строках, используя Promise.all() :

 const taskDataRef = firestore.collection('taskData');
const querySnapshot = await taskDataRef.get();

const promises = querySnapshot.docs.map(doc => doc.ref.collection('taskLog').get());

const querySnapshotsArray = Promise.all(promises);

querySnapshotsArray.forEach(querySnapshot => {
   
   // Do something with the querySnapshot
   // e.g. querySnapshot.docs....
   // or querySnapshot.forEach(...)

});
 

Если вы хотите объединить данные одного родителя ( taskData документа) вместе со всеми дочерними taskLog документами, обратите внимание, что Promise.all() возвращает одно обещание, которое преобразуется в массив результатов входных обещаний, который находится в том же порядке, что и входной массив. Другими словами, querySnapshotsArray имеет тот же порядок, что promises и .


Обратите внимание, что это будет стоить чтения ВСЕХ документов TaskData и ВСЕХ документов журнала задач из ВСЕХ taskLog вложенных коллекций. Может быть менее сложно организовать ваш интерфейс таким образом, чтобы вложенные коллекции извлекались только по требованию (например, если пользователь нажимает на кнопку или расширяет раздел и т. Д.)

Комментарии:

1. Я понимаю, что вы бы порекомендовали создать массив с именем taskLogs вместо создания их в вложенной коллекции? Я понимаю с точки зрения чтения, но я думаю о расширении функциональности позже, возможно, фильтрации поиска по дате и пользователям.

2. «не могли бы вы порекомендовать создать массив с именем taskLogs вместо того, чтобы создавать их в вложенной коллекции» => Это сложно ответить с доступным объемом информации. Это сильно зависит от запросов, которые вы хотите выполнить из своего интерфейса. Например, вас может заинтересовать фильтрация журналов задач по дате для конкретной TaskData => вложенная коллекция делает sebnse в этом случае… Также обратите внимание, что для документа Firestore doc существует ограничение на размер в 1 МБАЙТ => Если ваш массив taskLogs содержит много элементов, вы можете достичь предела.

3. Да, вот почему я выбрал этот подход. Если не так много вопросов, можете ли вы расширить часть querySnapshot? Я получаю сообщение об querySnapshotsArray.forEach(doc => { ошибке, возможно, ограничить количество документов до 5, отсортированных по дате, чтобы запрос не читал много документов?

4. querySnapshotsArray это не массив DocumentSnapshot s, а querySnapshot s. Вот почему вам нужно выполнить цикл дважды: на querySnapshotsArray , а затем на каждом querySnapshot .

5. @CookieMonster Привет, у тебя было время посмотреть ответ?