Home > Back-end >  How to map over an observed array to combine multiple obervables latest values
How to map over an observed array to combine multiple obervables latest values

Time:11-21

I am piping into an observable, that streams an array of let's say food. I need to get the latest cook, the latest kitchen, and the latest knife used to prepare each of these food items. These three values are all values got by an observable like getCookById(food.cook.id). How could i map it so:

  • I'm waiting for the array of food
  • When i receive it, I map on every food item to:
    • get latest cook, kitchen and knife that are all from Observables (combineLatest?)
    • combine all of that on an object like
{
   foodItem,
   cook,
   kitchen,
   knife
}
  • return the array of all these transformed items

Currently, I get an array of empty items doing it like so :

    const foodObservable = new Subject();
    
    foodObservable.pipe(
      map(foodItems => {
        return foodItems.map((foodItem: any)=>{
          const cookObservable = new Subject();
          const kitchenObservable = new Subject();
          const knifeObservable = new Subject();

          combineLatest(cookObservable, kitchenObservable, knifeObservable).subscribe(([cook, kitchen, knife]) => {
            return {
              foodItem,
              cook,
              kitchen,
              knife
            };
          });
        })
      })
    ).subscribe(foodPreparationArray=>{
      console.log(foodPreparationArray) // array of empty values :(
    })
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Based on your condition and your comment, I'd suggest the following changes

  1. You'd need to use a higher order mapping operator like switchMap to map from one observable to another. map operator is used to transform the emitted data.

  2. Using Firebase get() instead of valueChanges() would be a better fit. I assume you need the value at the moment and do not need to observe any changes to the property. See here for more info.

  3. Using get() instead of valueChanges() provides us with us observables that completes instead of streaming. So you could replace the combineLatest with forkJoin.

  4. You'd need two forkJoins. First forkJoin is to trigger requests for each element of the foodItems array and second forkJoin is to trigger requests for cook, knife, and kitchen simultaneously.

  5. Finally you could use the map operator to combining everything.

Try the following

foodObservable.pipe(
  switchMap((foodItems: any) =>                                            // <-- RxJS `switchMap` operator
    forkJoin(
      foodItems.map((foodItem: any) =>                                     // <-- JS `Array#map` function
        forkJoin({
          cook: db.collection('cook').doc(foodItem.cookId).get(),
          kitchen: db.collection('kitchen').doc(foodItem.kitchenId).get(),
          knife: db.collection('knife').doc(foodItem.knifeId).get()
        }).pipe(
          map(({cook, kitchen, knife}) => ({                               // <-- RxJS `map` operator
            ...foodItem,                                                   // <-- spread operator
            cook: cook,
            kitchen: kitchen,
            knife: knife
          )})
        )
      )
    )
  )
).subscribe({
  next: (foodPreparationArray: any) => {
    console.log(foodPreparationArray);
  },
  error: (error: any) => {
    // handle error
  }
});
  • Related