Dreanaught
Dreanaught

Reputation: 71

Joining flattened data

I'd like to join data from my trainings-table into my users-table.

The data structure it like this:

 - users
  - key1
     - name
     - trainingIds
         - t_key1
         - t_key3
 - trainings
  - t_key1
     - name
     - description
  - t_key2
     - name
     - description
  - t_key3
     - name
     - description

I've already searched Stackoverflow and found a nice solution. Unfortunately, I wasn't able to solve the problem mentioned by Romain Bruckert.

This is my code:

this.visibleUser$ = af.database.list(`${this.path}`)
        .map( users => {
          console.log( users );
          return users.map( user => {
            console.log( user );
            console.log( user.trainingIds );
            user.trainingIds.map( trainingIdsMap => {
              af.database.list(`dev/trainings/${trainingIdsMap.$key}`)
              .map( tr => {
                trainingIdsMap = tr;
              });
            });
            return user
          });
        }) as FirebaseListObservable<any>;

This is the Firebase data structure:

{
  "trainings" : {
    "-KdGENe4XiCyEowgYGbu" : {
      "description" : "lala beschreibung",
      "name" : "Bring Sally Up Challenge"
    },
    "-KdGGjQtvdLPWZOSHjKP" : {
      "description" : "Beschreibung für liegestütz",
      "name" : "Ligestütze"
    },
    "-KdGH3qNKCWGnW1kebMj" : {
      "active" : false,
      "description" : "Des funktioniert ja wirklich",
      "name" : "Wahnsinn"
    },
    "-KdHSzTb63L9_6qw461X" : {
      "description" : "klettern klettern klettern",
      "name" : "8a Training"
    },
    "-KdI2OXgEO0GnIqDXaDT" : {
      "description" : "Bes",
      "name" : "Test"
    }
  },
  "users" : {
    "8faYwT4xp4SoXzU3HPnc2rIsqyp1" : {
      "email" : "[email protected]",
      "trainingIds" : {
        "-KdGH3qNKCWGnW1kebMj" : false,
        "-KdHSzTb63L9_6qw461X" : true
      },
      "username" : "didi"
    },
    "EWt2O16J9MasAwuoi92PQ3h66Bw2" : {
      "email" : "[email protected]",
      "username" : "ChrisB"
    }
  }
}

As suggested by Clark, I already imported the rxjs map operator, but this does not solve the problem. The problem seems to be the list of trainingIds. These aren't returned as an array as expected but rather as an object. This can be seen in the console log.

Consolelog:

Any Idea how to solve this problem?

Upvotes: 1

Views: 176

Answers (1)

AngularChef
AngularChef

Reputation: 14087

Here's a working solution.

Check out a live Plunker of this code. You'll see that the console logs the users along with their resolved trainings.

const visibleUser$ = user$
  // Flatten the array of users to emit users individually.
  .mergeMap(val => val)
  // Project each user to an observable to get its trainings.
  .mergeMap(user => {
    // Array of observables fetching the trainings for the current user.
    const trainingsArr = user.trainingIds.map(trainingId => getTraining(trainingId));
    // Unwrap the trainings and merge them with the current user.
    return Rx.Observable.from(trainingsArr)
      .mergeAll()
      .toArray()
      .map(userTrainings => Object.assign(user, {trainings: userTrainings}));
  })
  .toArray()

visibleUser$.subscribe(val => console.log(val));

The console will log:

[{
  key: "key1",
  name: "user1",
  trainingIds: ["t_key1", "t_key3"],
  trainings: [  // Array of unwrapped trainings for this user
    {
      desc: "Desc 1",
      key: "t_key1",
      name: "Training 1"
    },
    {
      desc: "Desc 3",
      key: "t_key3",
      name: "Training 3"
    }
  ]
},
{
  key: "key2",
  name: "user2",
  // ...
}]

In the Plunkr, I have substituted the live Firebase calls with observables wrapping fake data. More specifically in my example you need to replace:

  • user$ with af.database.list(this.path)
  • getTraining(trainingId) with af.database.list(dev/trainings/${trainingIdsMap.$key})

Let me know if you have questions about the code.

Minor side note: in your code "af.database.list(${this.path})" can be replaced with af.database.list(this.path). No need for interpolation if all the string contains is a variable. :)

Upvotes: 1

Related Questions