我尝试了等待/异步方法来检索与我的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));
}
答案 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;
}