从 Firestore 的一个集合中获取所有文档
Posted
技术标签:
【中文标题】从 Firestore 的一个集合中获取所有文档【英文标题】:Getting all documents from one collection in Firestore 【发布时间】:2019-02-05 13:55:33 【问题描述】:您好,我从 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 未定义,为什么?
【问题讨论】:
【参考方案1】:另一个答案中的示例过于复杂。如果您只想为查询或集合中的每个文档返回原始数据对象,这将更直接:
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 仅当您的导入/要求与 OP 所做的不同时才会起作用。
这将计入一次读取配额,还是将集合中的每个文档都算作一次读取操作?
@Mentor 该查询将读取每个匹配的文档,无论您如何处理代码中的快照。
@bermick 一次查询是一次往返。查询的全部结果会在快照中返回。【参考方案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)
)
【讨论】:
【参考方案3】:我是这样设计的:
async getMarkers()
const markers = [];
await firebase.firestore().collection('events').get()
.then(querySnapshot =>
querySnapshot.docs.forEach(doc =>
markers.push(doc.data());
);
);
return markers;
【讨论】:
【参考方案4】:如果您需要在响应中包含文档的键,另一种选择是:
async getMarker()
const snapshot = await firebase.firestore().collection('events').get()
const documents = [];
snapshot.forEach(doc =>
documents[doc.id] = doc.data();
);
return documents;
【讨论】:
【参考方案5】:您可以将整个集合作为一个对象,而不是像这样的数组:
async getMarker()
const snapshot = await firebase.firestore().collection('events').get()
const collection = ;
snapshot.forEach(doc =>
collection[doc.id] = doc.data();
);
return collection;
这会让您更好地了解 Firestore 中的内容。数组没有错,只是另一种选择。
【讨论】:
【参考方案6】:我更喜欢在我的服务中隐藏所有代码复杂性......所以,我通常使用这样的东西:
在我的 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】:晚了两年,但我最近才开始阅读 Firestore 文档以获取乐趣,发现withConverter
没有在上述任何答案中发布。因此:
如果您想包含 id 并且也使用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>
回来!(不是@987654337 @ 返回。)这就是withConverter
的全部意义...这样,如果您有任何对象方法(本示例中未显示),您可以立即使用它们。)
这对我来说是有道理的,但我想我已经变得如此贪婪/被宠坏了,以至于我只是有点期望我的 VS 代码、ESLint 和 TS Watcher 真正为我做一切。 ? 哦,好吧。
正式文档(关于 withConverter
等)在这里:https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects
【讨论】:
【参考方案8】:这是最佳答案的简单版本,但进入一个带有文档 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;
, );
【讨论】:
【参考方案9】:docs 状态:
import collection, getDocs from "firebase/firestore";
const querySnapshot = await getDocs(collection(db, "cities"));
querySnapshot.forEach((doc) =>
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
);
但是我正在使用以下内容(请原谅 TypeScript):
import collection, Firestore, getDocs, Query, QueryDocumentSnapshot, QuerySnapshot from 'firebase/firestore'
const q: Query<any> = collection(db, 'videos')
const querySnapshot: QuerySnapshot<IVideoProcessed> = await getDocs(q)
const docs: QueryDocumentSnapshot<IVideoProcessed>[] = querySnapshot.docs
const videos: IVideoProcessed[] = docs.map((doc: QueryDocumentSnapshot<IVideoProcessed>) => doc.data())
其中 db 的类型为 Firestore
【讨论】:
【参考方案10】:我了解您的查询,这是因为 Javascript 如何处理承诺和变量。所以基本上 events 变量被提升为 undefined 值并打印在 LOG 2 控制台日志上,而负责 promise 调用的事件循环产生一个对象数组作为 events 变量的值,然后是控制台日志 (LOG 1)打印了已解决的承诺响应
【讨论】:
【参考方案11】:所有答案都是正确的,但是当您有大量数据时,您将面临内存和带宽问题,因此您必须编写一个 [cursor] 函数来部分读取数据。
另外,您可能会遇到带宽耗尽错误,请查看我在 gist 上实施的这个解决方案 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();
【讨论】:
以上是关于从 Firestore 的一个集合中获取所有文档的主要内容,如果未能解决你的问题,请参考以下文章
从嵌套在Firestore中的文档中的集合中获取数据的最佳方法是什么?
我可以获取从 Firestore 集合组查询中获取的文档的路径或引用吗?