2

I've got a question about dealing with working with many-to-many relationships in Firebase. Basically, I'm trying to build a user profile object from multiple paths inside of my Firebase data. I've tried building a function that returns an observable and then updates the data in that observable as a nested observable grabs data from Firebase.

The problem is that the nested observable doesn't ever get called, from what I can tell. I've been beating my head against this for hours without any real success. Can anyone tell what I'm doing wrong? I feel this is a pretty common problem that gets solved.

public getUserProfile(data) {

    return this._af.database.object(`/social/users/${data.id}`).map((user) => {
        for ( let vidKey in user.videos) {

            // Once the code hits this line, it never fires at all :(
            this._af.database.object(`/social/videos/${vidKey}`).map((video) => {
                user.videos[vidKey] = video;
            });
        }
        return user;
    });
}

1 Answer 1

5

The nested observable is never called because it's never subscribed to - observables are lazy.

You could do something like this, instead:

public getUserProfile(data) {

  return this._af.database
    .object(`/social/users/${data.id}`)

    // Switch to the joined observable

    .switchMap((user) => {

      let vidKeys = Object.keys(user.videos);

      // Use forkJoin to join the video observables. The observables will
      // need to complete, so first is used. And use forkJoin's selector to
      // map the videos to the user and then return the user.

      return Observable.forkJoin(
        vidKeys.map((vidKey) => this._af.database
          .object(`/social/videos/${vidKey}`)
          .first()
        ),
        (...videos) => {
          vidKeys.forEach((vidKey, index) => { user.videos[vidKey] = videos[index] });
          return user;
        }
      );
    });
}
Sign up to request clarification or add additional context in comments.

8 Comments

cartant, you are the absolute best. I've realized this is one of those instances where I'll be reusing this kind of functionality a lot for a number of different "join-esque" things I'll be doing. This works perfectly and it actually showcases a concise way to do it :) Cheers!
Actually, I was curious: If I wanted my UI to automatically update video details if they change elsewhere, would I need to rework this to use subscribes of each individual video from the Firebase database? In your current version, video data is only loaded once but not updated, if updated in the database. My thinking is that I'd like to use this same functionality for aggregating messages between users or a feed of different posts.
Yep, you would need to change it. The code in the answer will only re-emit if the user changes. If you want to re-emit when anything changes, you can use combineLatest instead of forkJoin. And remove the first operator, too.
That's awesome :) I did try that out and I noticed that, yes, when I change anything on either the user or the videos, the objects update...but only just once. Any time I make changes after that initial change, they aren't reflected in the UI. Do you have any idea what might be causing that?
Remove the first operator from the observables passed to combineLatest.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.