简体   繁体   English

从 Firestore 的一个集合中获取所有文档

[英]Getting all documents from one collection in Firestore

Hi I'm starting with javascript and react-native and I'm trying to figure out this problem for hours now.嗨,我从 javascript 和 react-native 开始,我正在尝试解决这个问题几个小时。 Can someone explain me how to get all the documents from firestore collection ?有人可以解释一下如何从 firestore 集合中获取所有文件吗?

I have been trying this:我一直在尝试这个:

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

The example in the other answer is unnecessarily complex.另一个答案中的示例不必要地复杂。 This would be more straightforward, if all you want to do is return the raw data objects for each document in a query or collection:如果您只想为查询或集合中的每个文档返回原始数据对象,这将更直接:

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

if you want include Id如果你想包括 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)
    })
}

Same way with array与数组相同的方式

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

I made it work this way:我让它这样工作:

async getMarkers() {
  const markers = [];
  await firebase.firestore().collection('events').get()
    .then(querySnapshot => {
      querySnapshot.docs.forEach(doc => {
      markers.push(doc.data());
    });
  });
  return markers;
}

if you need to include the key of the document in the response, another alternative is:如果您需要在响应中包含文档的键,另一种选择是:

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

You could get the whole collection as an object, rather than array like this:您可以将整个集合作为一个对象,而不是像这样的数组:

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

That would give you a better representation of what's in firestore.这将使您更好地表示 firestore 中的内容。 Nothing wrong with an array, just another option.数组没有错,只是另一种选择。

I prefer to hide all code complexity in my services... so, I generally use something like this:我更喜欢在我的服务中隐藏所有代码复杂性......所以,我通常使用这样的东西:

In my events.service.ts在我的 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);
        });
    }

In my sth.page.ts在我的 sth.page.ts

   myList: Event[];

   construct(private service: EventsService){}

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

Enjoy :)享受 :)

Here's a simple version of the top answer, but going into an object with the document ids:这是最佳答案的一个简单版本,但进入具有文档 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;
            }, {});
}

Two years late but I just began reading the Firestore documentation recently cover to cover for fun and found withConverter which I saw wasn't posted in any of the above answers.晚了两年,但我最近才开始阅读 Firestore 文档以获取乐趣,并发现我看到的withConverter没有发布在上述任何答案中。 Thus:因此:

If you want to include ids and also use withConverter (Firestore's version of ORMs, like ActiveRecord for Ruby on Rails, Entity Framework for .NET, etc), then this might be useful for you:如果您想包含 id使用withConverter (Firestore 的 ORM 版本,如 Ruby on Rails 的 ActiveRecord、.NET 的实体框架等),那么这可能对您有用:

Somewhere in your project, you probably have your Event model properly defined.在您的项目中,您可能已经正确定义了Event模型。 For example, something like:例如,类似于:

Your model (in TypeScript ): ./models/Event.js您的模型(在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)
  }
}

And then your client-side TypeScript code:然后是您的客户端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())

  ...
}

Two interesting quirks of Firestore to notice (or at least, I thought were interesting): Firestore 的两个有趣的怪癖要注意(或者至少,我认为很有趣):

  1. Your event.id is actually stored "one-level-up" in snapshot.id and not snapshot.data() .您的event.id实际上存储在snapshot.id不是snapshot.data() “一级”。

  2. If you're using TypeScript, the TS linter (or whatever it's called) sadly isn't smart enough to understand:如果您使用的是 TypeScript,遗憾的是 TS linter(或其他任何名称)不够聪明,无法理解:

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

even though right above it you explicitly stated: .withConverter(eventConverter)即使在它上面你明确指出: .withConverter(eventConverter)

Which is why it needs to be doc: any .这就是为什么它需要是doc: any

( But! You will actually 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.) 但是!实际上会得到Array<Event>回来!(不是Array<Map>回来。)这就是withConverter的全部意义......这样如果你有任何对象方法(在这个例子中没有显示),你可以立即使用它们。)

It makes sense to me but I guess I've gotten so greedy/spoiled that I just kinda expect my VS Code, ESLint, and the TS Watcher to literally do everything for me.这对我来说很有意义,但我想我已经变得如此贪婪/被宠坏了,以至于我有点期待我的 VS Code、ESLint 和 TS Watcher 为我做任何事情 😇 Oh well. 😇 哦,好吧。


Formal docs (about withConverter and more) here: https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects此处的正式文档(关于withConverter等): https : withConverter

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

However I am using the following (excuse the TypeScript):但是我正在使用以下内容(请原谅 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())

where db has the type Firestore其中 db 的类型为Firestore

General example to get products from Cloud Firestore:从 Cloud Firestore 获取产品的一般示例:

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

Try following LOCs尝试遵循 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;

I understand your query, This is because how Javascript handles promises and variables.我理解您的查询,这是因为 Javascript 如何处理承诺和变量。 So basically events variable is hoisted with the value undefined and printed on the LOG 2 console log, while the Event Loop responsible for the promise call resulted in an array of objects as the value of the events variable and then the console log (LOG 1) was printed with the resolved promise response所以基本上events变量的值是undefined并打印在LOG 2控制台日志上,而负责promise调用的事件循环产生了一个对象数组作为events变量的值,然后是控制台日志(LOG 1)与已解决的承诺响应一起打印

All answers are true, but when you have heavy data you will face memory and bandwidth problems, so you have to write a [cursor] function to read data part by part.所有的答案都是正确的,但是当您有大量数据时,您将面临内存和带宽问题,因此您必须编写一个[cursor]函数来部分读取数据。

also, you may face to Bandwidth Exhausted error, please have a look at this solution I have implemented on a gist https://gist.github.com/navidshad/973e9c594a63838d1ebb8f2c2495cf87此外,您可能会遇到带宽耗尽错误,请查看我在 gist 上实施的此解决方案https://gist.github.com/navidshad/973e9c594a63838d1ebb8f2c2495cf87

Otherwise, you can use this cursor I written to read a collection 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM