最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - rxjs combining 2 objects together from 2 different observables - Stack Overflow

matteradmin6PV0评论

I have 2 observables that are listening for a database call respectively. I need to merge the 2 arrays together. If I have the following arrays

array1 = [{id: 1, content1: "string"}, {id: 2, content2: "string"}, {id: 3, content3: "string"}]
array2 = [{id: 1, contentX: "string"}, {id: 2, contentY: "string"}, {id: 3, contentZ: "string"}]

I want to merge them together so that I get a single observable array like this:

[{id:1, content1:"string", contentX:"string"}, {id:2, content2:"string", contentY:"string"}, {id:3, content3:"string", contentZ:"string"}]

I have some code but I'm really confused on how to proceed, I can't seem to find the right operators or chain them properly, does anyone have a good explanation on how to proceed? This is what I have so far, but literally don't know how to go on.

    const observable1 = getDataFromDb1();
    const observable2= getDataFromDb2();

    observable1 .pipe(
        bineLatest(observable2),
        flatMap(x => {
            //what to do here???
        })
    ).subscribe(
        (value)=>{
            console.log(value);
        }
    )

Thanks for your time

I have 2 observables that are listening for a database call respectively. I need to merge the 2 arrays together. If I have the following arrays

array1 = [{id: 1, content1: "string"}, {id: 2, content2: "string"}, {id: 3, content3: "string"}]
array2 = [{id: 1, contentX: "string"}, {id: 2, contentY: "string"}, {id: 3, contentZ: "string"}]

I want to merge them together so that I get a single observable array like this:

[{id:1, content1:"string", contentX:"string"}, {id:2, content2:"string", contentY:"string"}, {id:3, content3:"string", contentZ:"string"}]

I have some code but I'm really confused on how to proceed, I can't seem to find the right operators or chain them properly, does anyone have a good explanation on how to proceed? This is what I have so far, but literally don't know how to go on.

    const observable1 = getDataFromDb1();
    const observable2= getDataFromDb2();

    observable1 .pipe(
        bineLatest(observable2),
        flatMap(x => {
            //what to do here???
        })
    ).subscribe(
        (value)=>{
            console.log(value);
        }
    )

Thanks for your time

Share Improve this question asked Jul 2, 2018 at 16:15 SivvioSivvio 2972 gold badges9 silver badges22 bronze badges 10
  • 1 Rx.Observable.merge(observable1, observable2).subscribe(x => console.log(x)); – ramiz4 Commented Jul 2, 2018 at 16:31
  • is your observable emitting an array [{id: 1, content1: "string"}] or an object {id: 1, content1: "string"}? – CozyAzure Commented Jul 3, 2018 at 3:10
  • Can you describe how observable1 and observable2 emit their values (individually or all in one go)? And how is the relationship defined? Will there always be a id matching record in both sets? What should happen if their isn't? – Yoshi Commented Jul 3, 2018 at 7:30
  • observable1 and 2 are http calls to 2 different databases @Yoshi. So the results will e at different time from 2 different locations. There will always be an id matching – Sivvio Commented Jul 3, 2018 at 9:13
  • @CozyAzure when I console log the emitting array it es as an array of objects – Sivvio Commented Jul 3, 2018 at 9:14
 |  Show 5 more ments

2 Answers 2

Reset to default 3

I'm taking a wild guess here, and assume that both source-observables emit their values in one big chunk. If that's the case, you simply want to map both emissions to a custom merged one (otherwise please leave a ment). E.g.:

const { of, bineLatest } = rxjs;
const { map } = rxjs.operators;

// simple merge-by-id
const mergeById = ([t, s]) => t.map(p => Object.assign({}, p, s.find(q => p.id === q.id)));

const db1$ = of([
  {id: 1, content1: 'string'},
  {id: 2, content2: 'string'},
  {id: 3, content3: 'string'},
]);

const db2$ = of([
  {id: 1, contentX: 'string'},
  {id: 2, contentY: 'string'},
  {id: 3, contentZ: 'string'},
]);

const all$ = bineLatest(db1$, db2$).pipe(
  map(mergeById)
);

all$.subscribe(console.log);
<script src="https://unpkg./[email protected]/bundles/rxjs.umd.min.js"></script>

I tested 3 ways of doing this:

const entityList1 = [{id: 1, name: 'Bob'}, {id: 2, name: 'John'}, {id: 3, name: 'Mike'}];
const entityList2 = [{id: 3, age: 22}, {id: 1, age: 25}, {id: 2, age: 20}];

Same version of @Yoshi:

// V0
console.time('V0')
const mergeListsById_v0 = bineLatest(of(entityList1), of(entityList2)).pipe(
  map(([t, s]) => t.map(p => Object.assign({}, p, s.find(q => p.id === q.id))))
).subscribe(x => {
  console.log('result V0:', x);
  console.timeEnd('V0')
});

Version using rxjs reduce operator:

// V1
console.time('V1')
const mergeListsById_v1 = merge(from(entityList1), from(entityList2)).pipe(
  reduce((entitiesById, entity) => {
    return {
      ...entitiesById,
      [entity.id]: {
        ...entitiesById[entity.id] || {},
        ...entity
      }
    };
  }, {}),
  map(entitiesById => Object.values(entitiesById)),
).subscribe(x => {
  console.log('result V1:', x);
  console.timeEnd('V1')
});

Version using the rxjs groupBy operator:

// V2
console.time('V2')
const mergeListsById_v2 = merge(from(entityList1), from(entityList2)).pipe(
  groupBy(entity => entity.id),
  mergeMap(groupedEntities$ => groupedEntities$.pipe(
    reduce((merged, entity) => ({...merged, ...entity}), {}))
  ),
  toArray()
).subscribe(x => {
  console.log('result V2:', x);
  console.timeEnd('V2')
});

You can play with these version here: https://stackblitz./edit/rxjs-6aqjf9?devtoolsheight=60

As you can see, in terms of performance, the V2 in much better than the others.

Post a comment

comment list (0)

  1. No comments so far