1
votes

Requirement: call an observable on remote server to get list of product ids. Call Firebase to get product detail (for each product id).

The following code works but it feels more like a promise implementation than an observable implementation. Note that code samples are simplified and somewhat pseudo code.

In theory, this could be solved by calling one Firebase observable that returns all products e.g. where productid in (35, 68). But I can't find a way to do this in Firebase. Instead I make one call for each product id.

this.predicitionioService.getProductIds()
    .subscribe(
            ids => {
                this.productService.getProduct(ids[0].id).subscribe(product => this.product1 = product);
                this.productService.getProduct(ids[1].id).subscribe(product => this.product2 = product);
            }
    );

flatMap is ballpark what's needed here. But the data returned is for the last product only.

this.predicitionioService.getProductIds()
.flatMap((ids) => this.productService.getProduct(ids[0].id))
.flatMap((ids) => this.productService.getProduct(ids[1].id))
.subscribe(

merge kind of gets me there but also returns product ids in the subscribe next function. And I need products to have an index e.g. product 1, 2, 3. I can't just bind a single list. This seems to work with assigning my own index e.g. i++. But again this gets messy.

this.predicitionioService.getProductIds()
.merge(
    this.productService.getProduct(ids[1].id),
    this.productService.getProduct(ids[2].id)
)
.subscribe(

Is there a better way of implementing this with observable methods?

2
just for clarification, you want to get a list of IDs and for every ID you want the product? And the result should be an associative array? - Dinistro

2 Answers

3
votes
var maxConcurrent = 5;

this.predicitionioService.getProductIds() // => Observable of array of ids, 1 item 
  .mergeMap(ids => Observable.from(ids))   // => Observable of ids
  .mergeMap(id => this.productService.getProduct(id.id), null, maxConcurrent) // => Observable of products
  .subscribe(product => { /* do stuff */ }); // do stuff to each product

Notes:

  • From RxJS 5, flatMap is an alias of mergeMap.
  • If you really need to get products as an array, prepend .subscribe with .toArray()
  • The maxConcurrent parameter is the maximum number of concurrent requests to getProduct. If you need to preserve the order of products (same order as in the original ids array), set this to 1 - but it will be slower. (mergeMap with maxConcurrent = 1 would be equivalent to concatMap)
  • 1
    votes

    This should do what you need:

    this.predicitionioService.getProductIds()
        .flatMap((ids) => {
            return Observable.forkJoin(
                ids.map(
                    (id) => this.productService.getProduct(id.id)
                )
            );
        })
        .subscribe((products) => {
            //do stuff
        });
    

    This will return an array with all results of the getProduct();