Привет, я начинаю с 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 не определен, почему?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я сделал так:
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());
}
@etoxin Это будет работать, только если ваш импорт / требования будут отличаться от того, что делал OP.
Будет ли это засчитываться в одно чтение для квоты, или каждый документ в коллекции будет считаться операцией чтения?
@Mentor Запрос будет считаться для каждого совпадающего документа, независимо от того, что вы делаете со снимками в своем коде.
const events = await firestore.collection('events').get().then(snapshot => snapshot.docs.map(doc => doc.data()))будет ли это одна поездка в базу данных или по одной для каждого документа?
@bermick one query - это один запрос туда и обратно. Полные результаты запроса возвращаются в снимок.
snapshot.docs больше не работает или устарел @DougStevenson
@MisterSirCode Нет, документы по-прежнему является свойством QuerySnapshot.
О, мои извинения, я перепутал базу данных Firebase Real-time и Firestore ... оказывается, я случайно попал в документацию по базе данных, а не в firestore, так что все хорошо
если вам нужно включить ключ документа в ответ, другой альтернативой является:
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 (по крайней мере, я подумал, что это интересно):
Ваш event.id фактически хранится «на один уровень выше» в snapshot.id и нетsnapshot.data().
Если вы используете 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();
}
это сработало для меня
const snapshot = await firestore.collection('events').get()