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
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.Using Firebase
get()
instead ofvalueChanges()
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.Using
get()
instead ofvalueChanges()
provides us with us observables that completes instead of streaming. So you could replace thecombineLatest
withforkJoin
.You'd need two
forkJoin
s. FirstforkJoin
is to trigger requests for each element of thefoodItems
array and secondforkJoin
is to trigger requests forcook
,knife
, andkitchen
simultaneously.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
}
});