Home > Software engineering >  Data manipulation inside an Observable RxJS
Data manipulation inside an Observable RxJS

Time:07-15

I would like to ask how would you write this observable to do what I want and whether it is a good practice to manipulate data with array operations inside an observable operator.

I am retrieving profile data to present, but inside it's profile.myTrades array it has id's. To show the name corresponding to the id's I need to retrieve another set of data which has all trades with their id's and names. Then I need to filter the names of the trades that have their ID's inside profile.myTrades and assign the result to profile.myTrades in order to show the names in the view.

It currently works, but I don't know whether it is the right way to write it.

    this.currentSwapOwner$ = combineLatest([
      // getting profile info
      this.userService.getProfileById(this.ownerId),
      // getting all trades ITrade[]
      this.tradeService.getTrades()
    ]).pipe(
      map(([profile, trades]) => {
      // filtering trades that have their ID inside profile.myTrades string[] and assigning filtered trades to profile.myTrades
        profile.myTrades = trades.filter(trade => profile.myTrades.includes(trade._id)).map(trade => trade.name);
        return profile;
      })
    )

CodePudding user response:

Filtering a huge set of trade set of data repeatedly can of course be expensive. I recommend a slightly different approach. Pseudo:

this.currentSwapOwner$ = combineLatest([
      this.userService.getProfileById(this.ownerId),
      this.tradeService.getTrades().pipe.map(/* map this to a map { [id]: tradesOfIdArray }*/),
    ]).pipe(
      map(([profile, tradesMap]) => {
        profile.myTrades = /*lookup id(s) in tradesMap*/, 
    )

CodePudding user response:

I think it's right to do this, but it can be optimised. @MoxxiManagarm's answer is a good one, if you have the trades as a record id -> Trade then the lookup will be much faster than calling includes.

Also, I assume trades is way bigger than just myTrades, so maybe instead of trades.filter it's better to start from profile.myTrades which would be smaller. If we do both of these optimisations, wouldn't this work?

this.currentSwapOwner$ = combineLatest([
  // getting profile info
  this.userService.getProfileById(this.ownerId),
  // getting all trades ITrade[]
  this.tradeService.getTrades().pipe(
    map(trades => keyBy(trades, '_id')) // keyBy is a common function available in e.g. lodash, can do it yourself too
  )
]).pipe(
  map(([profile, tradeMap]) => profile.myTrades.map(id => tradeMap[id].name))
)
  • Related