Reputation: 397
I'm trying to populate a collection of supermarket by adding the products to each supermarket, in an asynchronous way.
The objective is to pass from having something like this:
[{
name: 'supermarket x',
products: [1, 2]
}]
To something more like this:
[{
name: 'supermarket x',
products: [{
id: 1,
name: 'cacao'
}, {
id: 2,
name: 'milk'
}]
}]
I got to make the base code for this but I cannot achieve to populate the first stream with the second one once it's completed.
Any ideas?
I leave here a JSBin with the structure to make it faster for you
https://jsbin.com/nucutox/1/edit?js,console
Thanks!
Upvotes: 0
Views: 46
Reputation: 1761
So, you have a getSupermarkets()
function which returns a stream that emits multiple supermarket objects and a getProduct(id)
function which returns a stream that emits a single product with the specified id and then completes. And you want to map a stream of supermarkets containing product ids to a stream of supermarkets containing "resolved" product objects. Did I get this right?
Here's my solution:
const supermarkets$ = getSupermarkets()
.concatMap(supermarket => {
const productStreams = supermarket.products
.map(productId => getProduct(productId));
return Rx.Observable.combineLatest(productStreams)
.map(products => Object.assign({}, supermarket, { products }));
});
supermarkets$.subscribe(x => console.log(x));
When a new supermarket object arrives, we first map its array of product ids to an array of product observables, i.e. Array<Id> => Array<Observable<Product>>
. Then we pass that array to a combineLatest
operator which waits until each of the observables produces a value and emits an array of those values, i.e. an array of product objects. Then we produce a new supermarket object with products
set to the array. We want to keep the original supermarket
object unchanged, that's why Object.assign
.
To make it work I had to slightly update your implementation of getProduct()
: use .of(product)
operator instead of .from(product)
as product
is a plain object we want to emit.
Upvotes: 1