繁体   English   中英

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

[英]Getting all documents from one collection in Firestore

嗨,我从 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;
}

另一个答案中的示例不必要地复杂。 如果您只想为查询或集合中的每个文档返回原始数据对象,这将更直接:

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

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

我让它这样工作:

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

这将使您更好地表示 firestore 中的内容。 数组没有错,只是另一种选择。

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

在我的 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 getMarker() {
    const snapshot = await firebase.firestore().collection('events').get()
    return snapshot.docs.reduce(function (acc, doc, i) {
              acc[doc.id] = doc.data();
              return acc;
            }, {});
}

晚了两年,但我最近才开始阅读 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 的两个有趣的怪癖要注意(或者至少,我认为很有趣):

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

  2. 如果您使用的是 TypeScript,遗憾的是 TS linter(或其他任何名称)不够聪明,无法理解:

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

即使在它上面你明确指出: .withConverter(eventConverter)

这就是为什么它需要是doc: any

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

这对我来说很有意义,但我想我已经变得如此贪婪/被宠坏了,以至于我有点期待我的 VS Code、ESLint 和 TS Watcher 为我做任何事情 😇 哦,好吧。


此处的正式文档(关于withConverter等): https : withConverter

文档状态:

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

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

我理解您的查询,这是因为 Javascript 如何处理承诺和变量。 所以基本上events变量的值是undefined并打印在LOG 2控制台日志上,而负责promise调用的事件循环产生了一个对象数组作为events变量的值,然后是控制台日志(LOG 1)与已解决的承诺响应一起打印

所有的答案都是正确的,但是当您有大量数据时,您将面临内存和带宽问题,因此您必须编写一个[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();
}

暂无
暂无

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

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