0

I'm relatively new to Firebase, as well as the new Query API that comes along with it.

Basically, I've got a data store setup where users can add videos from YouTube that they showcase on their profiles. Since users can have many videos and videos can have many users, I've attempted to construct my data store in the appropriate fashion, based on best practices, as shown here:

{
    users {
     c25zdGFyb3NjaWFrQGdtYWlsLmNvbQ==
       videos {
         AFA-rOls8YA: true,
         AlLsp4gnyDQ: true,
         dX_1B0w7Hzc: true,
         ik5qR5bw75E: true,
         njos57IJf-0: true
       },
       videos {
         AFA-rOls8YA {
           attached_members {
             c25zdGFyb3NjaWFrQGdtYWlsLmNvbQ==: true
           }
           title: "Hello...it's me"
         },
         AlLsp4gnyDQ: { ... },
         dX_1B0w7Hzc: { ... },
         ik5qR5bw75E: { ... },
         njos57IJf-0: { ... },
         zn7-fVtT16k
        }
      }
    }
}

What can I do to query these objects in such a way where I can get back a single user that looks like this:

c25zdGFyb3NjaWFrQGdtYWlsLmNvbQ: {
  videos: {
     AFA-rOls8YA: {
       attached_members: { ... }
       title: "Hello...it's me"
     },
     AlLsp4gnyDQ: { ... },
     dX_1B0w7Hzc: { ... },
     ik5qR5bw75E: { ... },
     njos57IJf-0: { ... },
     zn7-fVtT16k: { ... }
  }
}

I have many instances where something like this is going to need to happen. I'm currently using Ionic 2, AngularFire 2, but can use the native Javascript SDK if needed. I see many posts about structuring the data in this way, but I don't see that posts as straight forward as answering how to get it in the most optimized modern way, with Firebase 3.

Any thoughts on how to do this?

Stevie Star
  • 2,331
  • 2
  • 28
  • 54

1 Answers1

1

So the reason they have you desegregate is to be able to bind to endpoints without loading a ton of data. If you had all your data under a single node when you load that node you'd get the entire tree.

We do what you are trying to do often, but it's not a single query call.

I see 2 main options,

One: A function to do a big loop over the results:

public getUser(userKey: string) {
  // assumes using af2
  return this.af.database.object('path/to/users/' + 'userKey').map((user) => {
    for ( let vidKey in user.videos) {
      if (user.videos.hasOwnProp(vidKey)) {
        this.af.database.object('path/to/vids/' + vidKey).map((video) => {
          user.videos[vidKey] = video;
        });
      }
    }
    return user;
  });
};

This would load your user as an object, then load each video and update the object when the data is loaded. Now I'd only use this method if you actually need one big object but I think you just want to display it in a list of users, then details on each vid:

Option 2: Smaller functions

TS:

// before constructor
public user = this.getUser('1234');

//after constructor
public getUser(userKey: string) {
  return this.af.database.object('path/to/users/' + userKey);
}
public getUserVids(userKey: string) {
 return this.af.database.list('path/to/users/' + userKey + '/videos');
}
public getVideo(vidKey: string) {
  return this.af.database.object('path/to/vids/' + vidKey);
}

In the template:

<div class="user" *ngIf="user">
    <h3>Name: {{user.name}}</h3>
    <div class="video" *ngFor="let video of geUserVids(user.$key) | async">
        <p>title: {{video.title}}</p>
        <p>length: {{video.length}}
    </div>
</div>

This way is much smaller and the functions could be used in different places. This uses the observables return from AF2 but is probably what you really want to do, not a giant json object...

Dennis Smolek
  • 8,480
  • 7
  • 30
  • 39
  • Thankyou so much for the concise answer, Dennis. Here's the thing, the first option is actually more along the lines of what I'm needing because I'm building a profile screen for a user on a mobile app, so not THAT much data, but enough where I need just one object. I'm finding that I create a function like the one you wrote out, but when I subscribe to the result of it, it doesn't seem to hit the nested for loop object calls to get the actual videos. Is there something weird going on with subscribe calls in this example? Or can you give me an example of what my component might look like? – Stevie Star Nov 14 '16 at 15:23
  • I think you should at least TRY the two call method, load the users, then load the vids.. But to answer my call doesn't use subscribe I'm mapping, so it returns the result of the map. You can try flatMap() too if you want a nested observable – Dennis Smolek Nov 14 '16 at 22:10