问题
I am making an expense manager webapp with angular 6. My database is on firebase. I am using the angularfire2 lib to retrieve and update the data.
the database is designed as follows
the function to get a category is
getCategory(uid:String,categorykey:string):Observable<any>
{
return this.afdb.object(`users/${uid}/categories/${categorykey}`)
.snapshotChanges()
.pipe(map(c=>({key:c.payload.key,...c.payload.val()})));}
the function that returns observable with an array of expenses is
getExpensesWithKeys(uid:String):Observable<any>{
return this.afdb.list(users/${uid}/expenses)
.snapshotChanges()
.pipe(
map(changes =>
changes.map(c =>
({key:c.payload.key,...c.payload.val()}))
)
);
}
In my component I can get my expenses as
expenses:Expense[];
getExpensesWithKey("userid-123")
.subscribe(expenses=>this.expenses=expenses)
and any category as
category:Category;
getCategory("userid-123",expenses[0].category)
.subscribe(category=>this.category=category);
I want to create an observable that gets the expenses array and returns the category for each expense which i can push into an array of categories. I've been racking my brain to combine the two observables with all kinds of rxjs operaters but to no avail.
Would really appreciate some help.
edit: Just wanted to add a few methods I tried already. One method I tried was
this.getExpensesWithKeys("user-123")
.pipe(mergeMap(expenses=>
expenses.map(expense=>
this.getCategory("user-123",expense.category)))).subscribe(console.log);
but it just emitting an array of Observables. How can i get the category objects and push them into an array?
Another method I tried
this.rtdbService.getExpensesWithKeys("user-123")
.pipe(map(expenses=>
expenses.map(expense=>expense.category)))
.pipe(mergeMap(ids=>
this.rtdbService.getCategory("user-123",ids)))
.subscribe(console.log);
This is only emitting the keys of the categories.
I also tried the below provided answer as well which is not emitting anything.
thanks in advance
回答1:
I finally found the solution
getExpensewithCategories(uid:String):Observable<any>{
;
let expwithCat$=this.getExpenses(uid).pipe(mergeMap(expenses =>{
return expenses.map(expense => this.getCategory(uid,expense.category)
.pipe(map(cat=>
({expensekey:expense.key,
amount:expense.amount,
date:expense.date,
expcatkey:expense.category,
categorykey:cat.key,
color:cat.color,
name:cat.name})
)
))
}
}));
return expwithCat$.pipe(mergeAll())
}
回答2:
Combine mergeMap
to chain observables with forkJoin
to make several calls at once :
getBothCategoryAndExpenses(uid) {
return this.getExpensesWithKeys(uid).pipe(
mergeMap(expenses => forkJoin(expenses.map(expense => this.getCategory(uid, expense.key)))
)
);
}
来源:https://stackoverflow.com/questions/51819588/angular-using-an-observable-within-an-observable