简体   繁体   中英

Combine RXJS observable results into one

I have two nodes in my database:

users: {user1: {uid: 'user1', name: "John"}, user2: {uid: 'user2', name: "Mario"}}
homework: {user1: {homeworkAnswer: "Sample answer"}}

Some users might or might not have a homework.

I want to obtain a list of all users with each user's homework data with a single call and subscribe. What would be the best way to achieve this?

Here is how the list obtained should look like for the example above:

[{uid: 'user1', name: "John", homework: {homeworkAnswer: "Sample answer"}}, {uid: 'user2', name: "Mario"}]

These are my two observables for users and homework :

let usersObservable = this.af.getObservable(`users/`);
let hwObservable = this.af.getObservable(`homework/`);

Basically you need to do two things, but there might be some details to consider.

  1. Get the data from both observables.
  2. Transform the data to your desired result.

The first step can easily be achieved by using forkJoin . In forkJoin you can pass in multiple observables and it will emit a value as soon as all observables have completed. Important: forkJoin only emits after completion. If your data comes from a store or a subject, you might have to add a take(1) operator so it actually completes.

The transformation part should be easy as well. I assume you want to have all users that exist in the user object, so we can use Object.keys to iterate over the existing user keys and then use map to transform the data.

// Imports:
import { forkJoin } from 'rxjs';
import { take } from 'rxjs/operators';

// Step 1: Use fork join to get the result from both observables
forkJoin(
    // pipe(take(1)) is only needed if the observables don't complete.
    usersObservable.pipe(take(1)), 
    hwObservable.pipe(take(1))
)
    // Step 2: Transform the data.
    // We now need to map our both results. We want to return all
    // users and add the homework if available. So we can user
    // Object.keys to iterate over the existing user keys in your object.
    .pipe(map(([users, homeworkMap]) => Object.keys(users)
        // Now we can map the keys to the actual user objects
        // and merge them with the homework
        .map(userKey => {
            const user = users[userKey];
            const homework = homeworkMap[userKey];
            return {
                ...user,
                homework
            };
        })
    ))
    .subscribe(users => console.log('Users: ', users));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM