最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin1浏览0评论

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.

发布评论

评论列表(0)

  1. 暂无评论