Search code examples
javascripttypescriptrxjsreactive-programming

RxJS - Properly merging two arrays from two seperate $http streams


Currently learning RxJS, I'm not gonna lie, I had difficulties understanding it, especially in terms of "Why do we even want to use if we have promises" But now I think I made small step further.

I know I should avoid nested subscriptions. Trying to write as short as possible code to merge two streams result into single variable.

So I have two arrays simulating result of streams, which I want to join. Fights array should became new obj array inside boxers objects

const boxers = [
    {
        user_id:1,
        first_name:'Lennox ',
        last_name:'Lewis',
        nationality:"UK"
    },
    {
        user_id:2,
        first_name:'Mike',
        last_name:'Tyson',
        nationality:'USA'
    },
     {
        user_id:3,
        first_name:'Riddick',
        last_name:'Bowe',
        nationality:'USA'
    },
];

const fights = [
    {
        fight_id:1,
        user_id:1,
        opponnent_id:2,
        winner_id:1,
        venue:'Memphis Pyramid, Tennessee'
    }
]

And then I wrote code:

const boxersWithFights2 = boxersStream.pipe(
    flatMap(boxers => {
        return fightsStream.pipe(
            flatMap(fights => {
                boxers.map(boxer => boxer.fights = fights.filter(fight => fight.user_id === boxer.user_id ||fight.opponnent_id === boxer.user_id ))
                return boxers;
            })
        )
    }
));

Surprisingly this works as expected. When I subscribe to boxersWithFights, it console.logs me with properly mapped objects. So it probably also work when returned from external api, but then I would of course need another map() operator.

My question: Is this code written well? Can it be written to be more clean & elegant ?

I also know I could do that easier with e.g. forkJoin, but I really wanted to test flatMap(mergeMap) operator.


Solution

  • You shouldn't mutate data in the stream but boxer.fights = does it. Also you can combine the streams together via forkJoin because they don't depend on each other.

    Try to use map operator instead:

    const boxersWithFights2 = forkJoin([boxersStream, fightsStream]).pipe(
        map(([boxers, fights]) => {
          return boxers.map(boxer => ({
            ...boxer,
            fights: fights.filter(fight => fight.user_id === boxer.user_id ||fight.opponnent_id === boxer.user_id ),
        })),
    ));