Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 pipe RxJs operator to chain 3 dependant observables

I have 3 dependent Rest API resources (lets say observables) like this:

1st observable produces one item as array of users, like this:

getUsers(): Observable<User[]>
    [
      {
        "id": 1,
        "name": "Peter",
        "surname": "Smith"
      },
      {
        "id": 2,
        "name": "John",
        "surname": "Wayne"
      },
      ...
    ]

2nd observable can be used to fetch addresses assigned to user, so the input parameter is User ID, and returns a one item as array of addresses:

getUserAddresses(user_id: string): Observable<Address[]>
    [
      {
        "id": 1,
        "city": "London",
        "street": "Wicombe 34"
      },
      {
        "id": 2,
        "city": "Paris",
        "street": "La fever 20"
      },
      ...
    ]

3rd observable can be used to fetch companies assigned to user, so the input parameter is User ID, and returns a one item as array of companies:

getUserCompanies(user_id: string): Observable<Company[]>
    [
      {
        "id": 1,
        "name": "Fintch CO",
        "state": "France"
      },
      {
        "id": 2,
        "name": "C&C inc.",
        "state": "USA"
      },
      ...
    ]

I want to chain these 3 observables into one which will produce the result again as one item, that will contain array of users with their additional addresses arrays and companies array, like following:

    [
      {
        "id": 1,
        "name": "Peter",
        "surname": "Smith",
        "addreesses": 
               [
                 {
                   "id": "1",
                   "city": "London",
                   "street": "Wicombe 34"
                 },
                 {
                   "id": "2",
                   "city": "",
                   "street": "La fever 20"
                 }
               ],
        "companies": 
               [
                 {
                   "id": "1",
                   "name": "Fintch CO",
                   "state": "France"
                 },
                 {
                   "id": "2",
                   "name": "C&C inc.",
                   "state": "USA"
                 }
               ]
        }
      },
      {
        "id": 2,
        "name": "John",
        "surname": "Wayne",
        "addresses": [...],
        "companies": [...],
      },
      ...
    ]

How should look like the operators composite to achieve that in Angular 6 with RxJs 6? Thanks a lot for advice.

like image 929
Peter Avatar asked Jul 06 '18 12:07

Peter


People also ask

Does pipe subscribe to Observable?

Using pipe to combine operators The pipe method accepts operators such as filter , map , as arguments. Each argument must be separated by a comma. The order of the operators is important because when a user subscribes to an observable, the pipe executes the operators in a sequence in which they are added.

What does pipe () do RxJS?

pipelink. pipe() can be called on one or more functions, each of which can take one argument ("UnaryFunction") and uses it to return a value. It returns a function that takes one argument, passes it to the first UnaryFunction, and then passes the result to the next one, passes that result to the next one, and so on.

What is Pipeable operator in RxJS?

A Pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified. A Pipeable Operator is essentially a pure function which takes one Observable as input and generates another Observable as output.


2 Answers

Something like this could work

getUsers()
.pipe(
  switchMap(users => from(users)),
  mergeMap(user => forkJoin(getAddresses(user.id), getCompanies(user.id))
                   .pipe(map(data => ({user, addresses: data[0], companies: data[1] })))
  tap(data => data.user.addresses = data.addresses),
  tap(data => data.user.companies = data.companies),
  map(data => data.user),
  toArray()
  )
)

Applied to a different use case a similar chain is explained in more details here.

like image 141
Picci Avatar answered Oct 17 '22 13:10

Picci


To chain observables, you can use the flatMap function. This function is like promises then, meaning the function is only executed once the observable has resolved to a value.

There is also an observable function called forkJoin which allows you to wait for multiple async requests to all have resolved to a value.

Example:

getUsers().flatMap((users) => {
    // the users variable is the list of users
    var multipleObservables = [];
    users.forEach((u) => {
      multipleObservables.push(
         getUserAddresses(u.id).map((usersAddresses) => {
            u.addresses = usersAddresses;
            return u;
         });
      );
    });
    return forkJoin(multipleObservables);
}).flatMap((usersWithAddresses) => {
    // the usersWithAddresses variable is an array of users which also have their addresses
    var multipleObservables = [];
    usersWithAddresses.forEach((u) => {
       multipleObservables.push(
          getUserCompanies(u.id).map((usersCompanies) => {
             u.companies = usersCompanies;
             return u;
          });
       );
    });
    return forkJoin(multipleObservables);
});

You can write something like this to chain you request and grow your user objects.

like image 28
brad mcallister Avatar answered Oct 17 '22 12:10

brad mcallister