0
votes

I have an API call that returns an observable collection of objects. For each object in that observable collection I need to do another API call to get an observable value.

What is the correct way to merge an observable collection with a collection of observables so that the result is an observable collection where we get rid of extra data ?

I.E: (1:n) -> 1

Concretely:

// getMarkets API response:
[   {
    "data": [
      {
        "mkt_name": "X",
        ...
      },
      {...}, {...}, {...} 
      //there is a lot of these, cardinality changes over time
    ]}
]
//getTicker(market=X) API response:
[   {
    "data": [
      {
        "last_trade": "651.4000000000",
        ...
      }
      //there is only one of this, "last_trade" value changes a lot more over time
    ],
    "notifications": []
    }
]

and I need

//getMarketsWithTickers Service response (! Also Observable !)
[ 
  {"market" : "X", "last_trade" : "651.4000000000" },  
  {...}, 
  {...}, 
  {...}
]

How do I implement getMarketWithTickers using getMarkets/getTicker observables ?

NOTE: I am new to this whole RxJS thing.

Thanks

1

1 Answers

3
votes

Here's a complete runnable example showing what you can do;

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/operator/map';

// what you already have (simulated):
interface Market {
  name: string;
}

interface Trade {
  lastTrade: string;
}

function getMarkets() {
  return Observable.of({data: [{name: 'm1'}, {name: 'm2'}, {name: 'm3'}] as Array<Market>})
}

function getTicker(marketName: string) {
  return Observable.of({data: {lastTrade: marketName.substring(1)}});
}

// what you can do:
getMarkets()
  .map(obj => obj.data.map(market => market.name)) //1
  .switchMap(marketNames =>
    Observable.forkJoin( // 4
      ...marketNames.map(market => getTicker(market) // 2
      .map(ticker => +ticker.data.lastTrade))) // 3
  )
  .subscribe(trades => console.log(trades.join(', ')));

Short explanation (read the documentation for more details):

  1. you transform your observable of collection of markets into an observable of market names using the map operator
  2. When you receive the array of market names, you create for each of them, an observable of Ticker.
  3. each observable of Ticker is transformed into an observable of lastTrade, one again using the map operator
  4. you use the forkJoin method to create an observable emitting an array containing the (last) emitted event of each of the observables of lastTrade