Roman Oxman
Roman Oxman

Reputation: 397

How can I populate a collection asynchronically?

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

Answers (1)

Sergey Karavaev
Sergey Karavaev

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

Related Questions