嗨,我从javascript和react-native开始,现在我想找出这个问题几个小时。有人可以解释一下如何从Firestore集合中获取所有文档吗?
我一直在尝试:
async getMarkers() {
const events = await firebase.firestore().collection('events').get()
.then(querySnapshot => {
querySnapshot.docs.map(doc => {
console.log('LOG 1', doc.data());
return doc.data();
});
});
console.log('LOG 2', events);
return events;
}
日志1打印所有对象(一个一个地打印),但是日志2未定义,为什么?
答案 0 :(得分:16)
另一个答案中的示例不必要地复杂。如果您要做的只是返回查询或集合中每个文档的原始数据对象,这将更简单:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
return snapshot.docs.map(doc => doc.data());
}
答案 1 :(得分:2)
如果要添加ID
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.log(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.log(tempDoc)
})
}
答案 2 :(得分:1)
我是这样工作的:
async getMarkers() {
const markers = [];
await firebase.firestore().collection('events').get()
.then(querySnapshot => {
querySnapshot.docs.forEach(doc => {
markers.push(doc.data());
});
});
return markers;
}
答案 3 :(得分:1)
这里是最简单答案的简单版本,但是进入了一个具有文档ID的对象:
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;
}, {});
}
答案 4 :(得分:0)
如果您需要在响应中包括文档的密钥,另一种选择是:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
const documents = [];
snapshot.forEach(doc => {
const document = {[doc.id}: doc.data()};
documents.push(document);
}
return documents;
}
答案 5 :(得分:0)
您可以将整个集合作为一个对象,而不是像这样的数组:
async getMarker() {
const snapshot = await firebase.firestore().collection('events').get()
const collection = {};
snapshot.forEach(doc => {
collection[doc.id] = doc.data();
});
return collection;
}
这将使您更好地表示Firestore中的内容。数组没问题,只是另一个选择。
答案 6 :(得分:0)
我更喜欢在服务中隐藏所有代码复杂性...因此,我通常使用类似以下的内容:
在我的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();
}
享受:)
答案 7 :(得分:0)
尝试遵循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;
答案 8 :(得分:0)
晚了两年,但我最近才开始阅读 Firestore 文档以获得乐趣,并发现我看到的 withConverter
没有发布在上述任何答案中。因此:
如果您想包含 ids 并且还使用 withConverter
(Firestore 的 ORM 版本,例如用于 Ruby on Rails 的 ActiveRecord、用于 .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 linter(或其他任何名称)不够聪明,无法理解:
const events = qs.docs.map((doc: Event) => doc.data())
即使在它的正上方,您也明确表示:
.withConverter(eventConverter)
这就是为什么它需要是 doc: any
。
(但是!你会实际上得到Array<Event>
的回报!(不是 Array<Map>
返回。)这就是 withConverter
的全部内容...这样,如果您有任何对象方法(本示例中未显示),您可以立即使用它们。)< /p>
这对我来说很有意义,但我想我已经变得如此贪婪/被宠坏了,以至于我有点期待我的 VS Code、ESLint 和 TS Watcher 为我做一切。 ? 哦,好吧。
此处的正式文档(关于 withConverter
及更多):https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects
答案 9 :(得分:0)
我理解您的查询,这是因为 Javascript 如何处理承诺和变量。所以基本上events变量的值是undefined并打印在LOG 2控制台日志上,而负责promise调用的Event Loop导致一个对象数组作为events变量的值,然后是控制台日志(LOG 1)与已解决的承诺响应一起打印
答案 10 :(得分:-1)
所有答案都是正确的,但是当你有大量数据时,你会面临内存和带宽问题,所以你必须编写一个[cursor]函数来部分读取数据。
此外,您可能会遇到带宽耗尽错误,请查看我在要点上实施的此解决方案 https://gist.github.com/navidshad/973e9c594a63838d1ebb8f2c2495cf87
否则,您可以使用我写的这个游标来逐个读取一个集合文档:
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.log(error);
})
}
// Read part by part
while (allowGoAhead) {
await getDocs();
}
onDone();
}