Search code examples
jsonjoinrxjsleft-join

How to left join two json array based on common id using RxJS


Need help on a problem with Rxjs join. I have two observables with common id, I want to perform join to show records from both objects based on id.

    let emp = of([
      { id: 1, name: 'aa', age: 20 },
      { id: 2, name: 'bb', age: 21 },
      { id: 3, name: 'cc', age: 22 },
      { id: 4, name: 'dd', age: 23 }
    ]);
   let details = of([
      { id: 1, address: 'ee' },
      { id: 1, address: 'ff' },
      { id: 2, address: 'gg' },
      { id: 2, address: 'hh' }
    ]);

I need the join like this:

[
 {id: 1, name: 'aa', age: 20, details: [{address: 'ee'},{address: 'ff'}] },
 {id: 2, name: 'bb', age: 21, details: [{address: 'gg'},{address: 'hh'}] },
 {id: 3, name: 'cc', age: 22, details: undefined },
 {id: 4, name: 'dd', age: 23, details: undefined },
]

I have tried like this:

  forkJoin([emp, details]).pipe(
      map(([_emp, _details]) =>
        _emp.map((item) => {
          return ( {
            ...item,
            details: _details.find((item1) => {
              return item1.id === item.id
            })
          })
        })
      )
    ).subscribe(console.log)

I got the result:

[
 {id: 1, name: 'aa', age: 20, details: [{address: 'ee'}] }, // {address: 'ff'} missing
 {id: 2, name: 'bb', age: 21, details: [{address: 'gg'}] }, // {address: 'hh'} missing
 {id: 3, name: 'cc', age: 22, details: undefined },
 {id: 4, name: 'dd', age: 23, details: undefined },
]

In this result second address is missing for id 1 and 2.

Instead of [{address: 'ee'},{address: 'ff'}], I got only first match [{address: 'ee'}] for id 1.

Instead of [{address: 'gg'},{address: 'hh'}], I got only first match [{address: 'gg'}] for id 2.

Please help me to accomplish the desired result


Solution

  • I think you should use filter() instead of find(). The find() operator returns only the first match.

      forkJoin([emp, details]).pipe(
          map(([_emp, _details]) =>
            _emp.map((item) => {
              return ({
                ...item,
                // This is the line you have to modify:
                details: _details.filter((item1) => item1.id === item.id)
              })
            })
          )
        ).subscribe(console.log)