1
votes

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

Database design

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

2

2 Answers

2
votes

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())
}
0
votes

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