未能成功检索子集合

时间:2019-05-27 01:35:31

标签: angular google-cloud-firestore

我尝试了等待/异步方法来检索与我的Firebase文档关联的集合。检索数据并将调试日志打印到控制台;但是,这是在调用函数返回之后。任何帮助,将不胜感激。我使用了Angular firestore文档:https://github.com/angular/angularfire2/blob/master/docs/firestore/collections.md

我正在使用数据订阅,并尝试在快照上等待

// Client call
async doSearch() {
const col = await this.service.getLogbookEntries(this.searchDoc.id)
      .then(entries => {
        for (let i = 0; i < entries.length; i++) {
          // Do something with entry
          const entry = entries[0];
        }
      });
}

// Collection retrieval
async getLogbookEntries(docId: string): Promise<LogbookEntry[]>
  // Retrieve sub collection and convert
  return new Promise((resolve) => {
    const entries: LogbookEntry[] = [];
    console.log("Retrieving logbook entries: ", docId);
    const doc = this.db.doc(`${this.endpoint}/${docId}`);
    doc.collection<Usage>("Usage").snapshotChanges()
      .subscribe(async a => {
          for (let i = 0; i < a.length; i++) {
            let data = a[i].payload.doc.data(); 
            let id = a[i].payload.doc.id;
            console.log("Cleaning ID: ", id, " Data: ", data);
            entries.push(this.toLogbookEntry(id, data);
          }
          resolve(entries);
        });
    });

即使等待返回的承诺,客户呼叫仍在返回。

更新 我能够基于以下情况得到适当的等待:

  async getLogbookEntries(docId: string): Promise<LogbookEntry[]> {
    const entries: LogbookEntry[] = [];
    console.log("Retrieving logbook entries: ", docId);
    const doc = this.db.doc(`${this.endpoint}/${docId}`);
    // Explicitly convert to promise.
    const cleaningCol = await doc.collection<ICleaning>("cleanings").get().toPromise();
    const cleaningsChanges = cleaningCol.docChanges();
    for (let i = 0; i < cleaningsChanges.length; i++) {
      const id = cleaningsChanges[i].doc.id;
      const data = cleaningsChanges[i].doc.data();
      console.log("Cleaning: ", data);
      entries.push(this.toLogbookEntry(id, LogbookType.Cleaning, data as ICleaning));
    }

1 个答案:

答案 0 :(得分:0)

问题的根本原因是,您混合了在Firebase文档中订阅数据和在Firebase文档中检索数据的概念(使用async / await)。您将需要使用一种模式或另一种模式(订阅模式或异步获取模式)来重构此解决方案。

    doSearchOnChanges() {
    const col = await this.service.getLogbookEntries(this.searchDoc.id, doStuffAfterRetrieval)
      function doStuffAfterRetrieval = entries => {
        for (let i = 0; i < entries.length; i++) {
          // Do something with entry
          const entry = entries[0];
        }
      };
     }

 // Collection retrieval
 getLogbookEntries(docId: string, doStuff: entry => void): void
  // Retrieve sub collection and convert
    const entries: LogbookEntry[] = [];
    console.log("Retrieving logbook entries: ", docId);
    const doc = this.db.doc(`${this.endpoint}/${docId}`);
    doc.collection<Usage>("Usage").snapshotChanges()
      .subscribe(async a => {
          for (let i = 0; i < a.length; i++) {
            let data = a[i].payload.doc.data(); 
            let id = a[i].payload.doc.id;
            console.log("Cleaning ID: ", id, " Data: ", data);
            entries.push(this.toLogbookEntry(id, data);
          }
          doStuff(entries);
        });

这或多或少是将代码重构为正确使用订阅的方式。我对firebase api不太熟悉,但是在粗略的Google搜索上获取数据而不订阅它,您需要在集合上使用.get()函数。 (另外,ProTip:不要在使用async / await时使用.then。它是多余的,然后会导致bug发生,否则就没有。选择一种模式并坚持使用。)

async doSearch() {
  const col = await this.service.getLogbookEntries(this.searchDoc.id);
  for (let i = 0; i < col.length; i++) {
    // Do something with entry
    const entry = entries[0];
  }
}

// Collection retrieval
async getLogbookEntries(docId: string): Promise<LogbookEntry[]> {
  // Retrieve sub collection and convert
  // Don't create your own promises. Async/Await and the Firbase API will do this for you
    const entries: LogbookEntry[] = [];
    console.log("Retrieving logbook entries: ", docId);
    const doc = this.db.doc(`${this.endpoint}/${docId}`);
    const returnedData = await doc.collection<Usage>("Usage").get();
    for (let i = 0; i < returnedData.length; i++) {
      let data = returnedData[i].payload.doc.data();
      let id = returnedData[i].payload.doc.id;
      console.log("Cleaning ID: ", id, " Data: ", data);
      entries.push(this.toLogbookEntry(id, data));
    }
    return entries;
}