Получение всех документов из одной коллекции в Firestore

Привет, я начинаю с javascript и react-native, и я уже несколько часов пытаюсь понять эту проблему. Может кто-нибудь объяснить мне, как получить все документы из пожарной коллекции?

Я пробовал это:

async getMarkers() {
  const events = await firebase.firestore().collection('events').get()
    .then(querySnapshot => {
      querySnapshot.docs.map(doc => {
        console.info('LOG 1', doc.data());
        return doc.data();
      });
    });
  console.info('LOG 2', events);
  return events;
}

Журнал 1 печатает все объекты (один за другим), но журнал 2 не определен, почему?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
88
0
125 943
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Я сделал так:

async getMarkers() {
  const markers = [];
  await firebase.firestore().collection('events').get()
    .then(querySnapshot => {
      querySnapshot.docs.forEach(doc => {
      markers.push(doc.data());
    });
  });
  return markers;
}
Ответ принят как подходящий

Пример в другом ответе излишне сложен. Это было бы проще, если бы все, что вам нужно было сделать, это вернуть необработанные объекты данных для каждого документа в запросе или коллекции:

async getMarker() {
    const snapshot = await firebase.firestore().collection('events').get()
    return snapshot.docs.map(doc => doc.data());
}

это сработало для меня const snapshot = await firestore.collection('events').get()

etoxin 08.07.2019 13:35

@etoxin Это будет работать, только если ваш импорт / требования будут отличаться от того, что делал OP.

Doug Stevenson 08.07.2019 13:36

Будет ли это засчитываться в одно чтение для квоты, или каждый документ в коллекции будет считаться операцией чтения?

Mentor 22.07.2019 20:50

@Mentor Запрос будет считаться для каждого совпадающего документа, независимо от того, что вы делаете со снимками в своем коде.

Doug Stevenson 22.07.2019 21:19
const events = await firestore.collection('events').get().then(snapshot => snapshot.docs.map(doc => doc.data()))
Oleksii.B 27.04.2020 09:01

будет ли это одна поездка в базу данных или по одной для каждого документа?

bermick 21.05.2020 20:54

@bermick one query - это один запрос туда и обратно. Полные результаты запроса возвращаются в снимок.

Doug Stevenson 21.05.2020 21:12

snapshot.docs больше не работает или устарел @DougStevenson

Mister SirCode 18.01.2021 23:24

@MisterSirCode Нет, документы по-прежнему является свойством QuerySnapshot.

Doug Stevenson 19.01.2021 04:59

О, мои извинения, я перепутал базу данных Firebase Real-time и Firestore ... оказывается, я случайно попал в документацию по базе данных, а не в firestore, так что все хорошо

Mister SirCode 19.01.2021 05:00

если вам нужно включить ключ документа в ответ, другой альтернативой является:

async getMarker() {
    const snapshot = await firebase.firestore().collection('events').get()
    const documents = [];
    snapshot.forEach(doc => {
       documents[doc.id] = doc.data();
    });
    return documents;
}

Вы можете получить всю коллекцию как объект, а не как массив:

async getMarker() {
    const snapshot = await firebase.firestore().collection('events').get()
    const collection = {};
    snapshot.forEach(doc => {
        collection[doc.id] = doc.data();
    });
    return collection;
}

Это даст вам лучшее представление о том, что находится в пожарном магазине. В массиве нет ничего плохого, просто еще один вариант.

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

В моем events.service.ts

    async getEvents() {
        const snapchot = await this.db.collection('events').ref.get();
        return new Promise <Event[]> (resolve => {
            const v = snapchot.docs.map(x => {
                const obj = x.data();
                obj.id = x.id;
                return obj as Event;
            });
            resolve(v);
        });
    }

На моем sth.page.ts

   myList: Event[];

   construct(private service: EventsService){}

   async ngOnInit() {
      this.myList = await this.service.getEvents();
   }

Наслаждаться :)

если вы хотите включить идентификатор

async getMarkers() {
  const events = await firebase.firestore().collection('events')
  events.get().then((querySnapshot) => {
      const tempDoc = querySnapshot.docs.map((doc) => {
        return { id: doc.id, ...doc.data() }
      })
      console.info(tempDoc)
    })
}

То же самое с массивом

async getMarkers() {
  const events = await firebase.firestore().collection('events')
  events.get().then((querySnapshot) => {
      const tempDoc = []
      querySnapshot.forEach((doc) => {
         tempDoc.push({ id: doc.id, ...doc.data() })
      })
      console.info(tempDoc)
   })
 }

Вот простая версия главного ответа, но для объекта с идентификаторами документов:

async getMarker() {
    const snapshot = await firebase.firestore().collection('events').get()
    return snapshot.docs.reduce(function (acc, doc, i) {
              acc[doc.id] = doc.data();
              return acc;
            }, {});
}

Попробуйте следовать LOC

    let query = firestore.collection('events');
    let response = [];
    await query.get().then(querySnapshot => {
          let docs = querySnapshot.docs;
          for (let doc of docs) {
              const selectedEvent = {
                     id: doc.id,
                     item: doc.data().event
                  };
             response.push(selectedEvent);
          }
   return response;

На два года позже, но я только недавно начал читать документацию Firestore от корки до корки для развлечения и обнаружил, что withConverter, который, как я видел, не был опубликован ни в одном из вышеперечисленных ответов. Таким образом:

Если вы хотите включить идентификаторы и, также используйте withConverter (версия ORM от Firestore, например ActiveRecord для Ruby on Rails, Entity Framework для .NET и т. д.), Тогда это может быть полезно для вас:

Возможно, где-то в вашем проекте ваша модель Event правильно определена. Например, что-то вроде:

Ваша модель (в TypeScript): ./models/Event.js

export class Event {
  constructor (
    public id: string,
    public title: string,
    public datetime: Date
  )
}

export const eventConverter = {
  toFirestore: function (event: Event) {
    return {
      // id: event.id,  // Note! Not in ".data()" of the model!
      title: event.title,
      datetime: event.datetime
    }
  },
  fromFirestore: function (snapshot: any, options: any) {
    const data = snapshot.data(options)
    const id = snapshot.id
    return new Event(id, data.title, data.datetime)
  }
}

А затем ваш клиентский код TypeScript:

import { eventConverter } from './models/Event.js'

...

async function loadEvents () {
  const qs = await firebase.firestore().collection('events')
    .orderBy('datetime').limit(3)  // Remember to limit return sizes!
    .withConverter(eventConverter).get()

  const events = qs.docs.map((doc: any) => doc.data())

  ...
}

Стоит обратить внимание на две интересные особенности Firestore (по крайней мере, я подумал, что это интересно):

  1. Ваш event.id фактически хранится «на один уровень выше» в snapshot.id и нетsnapshot.data().

  2. Если вы используете TypeScript, линтер TS (или как он там называется), к сожалению, недостаточно умен, чтобы понять:

const events = qs.docs.map((doc: Event) => doc.data())

хотя прямо над ним вы прямо заявили: .withConverter(eventConverter)

Вот почему это должен быть doc: any.

(Но! Вы получите фактически обратно! (Не Array<Event>). В этом вся суть Array<Map> ... Таким образом, если у вас есть какие-либо методы объекта (не показанные здесь в этом примере), вы можете немедленно их использовать.)

Для меня это имеет смысл, но я думаю, что я стал настолько жадным / испорченным, что я просто ожидал, что мой VS Code, ESLint и TS Watcher буквально сделают за меня все. ? Ну ладно.


Официальные документы (о withConverter и др.) Здесь: https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects

Я понимаю ваш запрос. Это связано с тем, как Javascript обрабатывает обещания и переменные. Таким образом, в основном переменная событий поднимается со значением undefined и печатается в журнале консоли LOG 2, в то время как цикл событий, ответственный за вызов обещания, привел к массиву объектов в качестве значения переменной событий, а затем к журналу консоли (LOG 1) был напечатан с разрешенным ответом на обещание

Все ответы верны, но когда у вас большой объем данных, вы столкнетесь с проблемами памяти и пропускной способности, поэтому вам придется написать функцию [курсор] для чтения данных по частям.

Кроме того, вы можете столкнуться с ошибкой исчерпанной пропускной способности, пожалуйста, ознакомьтесь с этим решением, которое я реализовал по сути https://gist.github.com/navidshad/973e9c594a63838d1ebb8f2c2495cf87

В противном случае вы можете использовать этот курсор, который я написал, чтобы прочитать документ коллекции по doc:

async function runCursor({
    collection,
    orderBy,
    limit = 1000,
    onDoc,
    onDone,
}) {
    let lastDoc;
    let allowGoAhead = true;

    const getDocs = () => {
        let query = admin.firestore().collection(collection).orderBy(orderBy).limit(limit)
        // Start from last part
        if (lastDoc) query = query.startAfter(lastDoc)

        return query.get().then(sp => {
            if (sp.docs.length > 0) {
                for (let i = 0; i < sp.docs.length; i++) {
                    const doc = sp.docs[i];
                    if (onDoc) onDoc(doc);
                }
                // define end of this part
                lastDoc = sp.docs[sp.docs.length - 1]
                // continue the cursor
                allowGoAhead = true
            } else {
                // stop cursor if there is not more docs
                allowGoAhead = false;
            }
        }).catch(error => {
            console.info(error);
        })
    }

    // Read part by part
    while (allowGoAhead) {
        await getDocs();
    }

    onDone();
}

Другие вопросы по теме