Suppose we have two observables
student$ = from([
{id: 1, name: "Alex"},
{id: 2, name: "Marry"},
])
address$ = from([
{id: 1, location: "Chicago", sid: 1},
{id: 2, location: "Florida", sid: 2},
])
I want to combine them into a array of object, the expected result would be following
studentAddress = [
{
id: 1,
name: "Alex",
address: [
{id: 1, location: "Chicago", sid: 1},
]
},
{
id: 2,
name: "Marry",
address: [
{id: 2, location: "Florida", sid: 2},
]
},
]
CodePudding user response:
You would want to use flatMap for that (RxJs method). Your first value would be needed by the second one. I am pasting an example code snippet below for flatMap() and also the article link there are other methods as well (the below example is from the same article link)
let first = Observable.of(10);
first.flatMap((operand1) => {
return Observable.of(operand1 10);
})
.subscribe(res => this.flatMappedStreams = {msg: '10 10 = ' res});
Check out this article here for concat
, combine
, forkJoin
etc
But the important thing is the way to achieve is RxJs Operators. You can also refer to their official docs for further understanding
CodePudding user response:
Considering your students$
and address$
observable emits an array of objects.
address$ = of([
{ id: 1, location: 'Chicago', sid: 1 },
{ id: 2, location: 'Florida', sid: 2 },
]);
students$ = of([
{ id: 1, name: 'Alex' },
{ id: 2, name: 'Marry' },
]);
Use RxJs function combineLatest: It Combines multiple Observables to create an Observable whose values are calculated from the latest values of each of its input Observables.
combineLatest
will not emit an initial value until each observable emits at least one value
combineLatest(
[this.students$, this.address$],
(students, address) =>
students.map((s) => ({
...s,
address: address.filter((a) => a.sid === s.id),
})) // combineLatest also takes an optional projection function
).subscribe(console.log);
imports used :
import { combineLatest, of } from 'rxjs';
Angular Demo by using combineLatest
and forkJoin
Note: In your case instead of combibeLatest
you can use forkJoin. forkJoin
only emits value When all observables are complete, emit the last emitted value from each.
CodePudding user response:
Taken from your comment that the arrays are obtained from nested HTTP calls, I'd say you need
switchMap
operator to map from one HTTP call to another (other higher order mapping operators)map
operator to transform the emission from the observableArray#map
withArray#filter
to do the actual combination of the arrays
var { of } = rxjs;
var { switchMap, map } = rxjs.operators;
const students$ = of([
{id: 1, name: "Alex"},
{id: 2, name: "Marry"},
]);
const addresses$ = of([
{id: 1, location: "Chicago", sid: 1},
{id: 2, location: "Florida", sid: 2},
]);
const result$ = students$.pipe(
switchMap(students =>
addresses$.pipe(
map(addresses =>
students.map(student => ({
...student,
address: addresses.filter(address => address.id === student.id)
}))
)
)
)
);
result$.subscribe(console.log);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>