从 Firestore 的一个收藏中获取所有文件

大家好,我从 javascript 和 response-national 开始,花了几个小时来解决这个问题。谁能给我解释一下如何从消防收集中取得所有的文件?

我一直在尝试:

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没有定义,为什么?

214641 次浏览

我是这么做的:

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());
}

如果您需要在回复中包含文档的密钥,另一种选择是:

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;
}

您可以将整个集合作为一个对象,而不是像下面这样的数组:

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

这样可以更好地表示 firestore 中的内容。数组没有什么问题,只是另一个选项而已。

我更喜欢在我的服务中隐藏所有的代码复杂性... 所以,我通常使用这样的东西:

In my 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();
}


享受:)

如果你想包括 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)
})
}

下面是顶部答案的一个简单版本,但是要进入一个带有文档 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;
}, {});
}

两年后,但我刚开始阅读火灾恢复文档最近涵盖为乐趣,并发现 withConverter,我看到没有张贴在任何以上的答案。因此:

如果您希望包含 id 还有,也可以使用 withConverter(Firest 的 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())


...
}


我们注意到了 Firest 的两个有趣的怪癖(或者至少我认为是有趣的) :

  1. 您的 event.id实际上是存储在 snapshot.id snapshot.data()“一级向上”。

  2. 如果你正在使用 TypeScript,那么 TS 行程(或者不管它叫什么)很遗憾没有足够的智能来理解:

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

尽管你在上面明确指出: .withConverter(eventConverter)

Which is why it needs to be doc: any.

(但是 You will 事实上 get Array<Event> back! (Not Array<Map> back.) That's the entire point of withConverter... That way if you have any object methods (not shown here in this example), you can immediately use them.)

这对我来说是有意义的,但我想我已经变得如此贪婪/娇惯,我只是有点希望我的 VS 代码,ESLint,和 TS 观察者字面上做 一切为我。好吧。


正式文档(关于 withConverter和更多)这里: https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects

我理解你的疑问,这是因为 Javascript 处理承诺和变量的方式。因此,基本上事件变量在未定义值的情况下悬挂起来,并打印在 LOG 2控制台日志中,而负责承诺调用的 Event Loop 会生成一个对象数组作为事件变量的值,然后控制台日志(LOG 1)会打印出已解析的承诺响应

所有的答案都是正确的,但是当您有大量数据时,您将面临内存和带宽问题,因此您必须编写一个[ cursor ]函数来逐部分读取数据。

此外,你可能会面临带宽耗尽的错误,请看看这个解决方案我已经实现了一个要点 Https://gist.github.com/navidshad/973e9c594a63838d1ebb8f2c2495cf87

否则,您可以使用我编写的这个光标来读取 doc by 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.log(error);
})
}


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


onDone();
}

The 医生 state:

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类型

从 Cloud Firest 获取产品的一般示例:

  Future<void> getAllProducts() async {
CollectionReference productsRef =
FirebaseFirestore.instance.collection('products');
final snapshot = await productsRef.get();
List<Map<String, dynamic>> map =
snapshot.docs.map((doc) => doc.data() as Map<String, dynamic>).toList();
}