So I just recently learn about denormalization and I am just trying to figure out the best way to structure my firebase database. What I currently have is I am displaying a users class schedule with the classes course number and intructor name. Firebase looks like this for me:
-root
-users
-uid1
-uid2
-schedules
-uid1 : true (match with users uid)
-uid2 : true (match with users uid)
-class
-classKey1
-users
-uid1 : true
-uid2 : true
-courseKey1 : true
-intructorKey1 : true
-classKey1
-users
-uid1
-courseKey2 : true
-intructorKey2 : true
-courses
-courseKey1
-intructors
-intructorKey1 : true
-intructorKey2 : true
-courseKey2
-similar to above
-intructors
-intructorKey1
-courses
-courseKey1: true
-courseKey2: true
-intructorKey2
-similar to above
Now, that is the basic structure of what I am working with, excluding all the unneeded information. Lets say I want to display all of the the schedule of the currently logged in user I will need to do the following.
_af.auth.subscribe(authState => {
let userID = authState.uid;
_af.database.list('/schedule/' + userID ).subscribe(schedule =>{
this.schedule = schedule; //global variable
this.filterClasses(); call function
});
});
_af.database.list('/class').subscribe(classes => {
this.masterClasses = classes; //gloabal variable
this.filterClasses();
});
Now because its all done asynchronously the only way I could think to do this is call the filterClasses function inside of each subscription.
filterClasses(): void {
if (this.scheduleKeys != null && this.masterClasses.length > 0) {
this.outputClasses = this.masterClasses.filter(value => {
let bool = false;
for (let i = 0; i < this.scheduleKeys.length; i++) {
if (this.scheduleKeys[i].$key === value.$key) {
bool = true;
break;
}
}
return bool;
});
this.outputClasses.forEach((value, i) => {
_af.database.object('courses/' + value.courseKey).subscribe(v => {
this.outputClasses[i]['courseNum'] = v.course;
})
_af.database.object('intructors/' + value.intructorKey).subscribe(v => {
this.outputClasses[i]['intructorName'] = v.name;
})
})
}
}
As you can see when I am done filtering my master list of classes into just the ones in my schedule I also now need to go and grab the course number firebase and the intructors name. Both of which require me to call firebase again. So to try and reduce researching firebase which seems to be causing some problems due to being async should I instead be denormalizing my data? Should in the class root of firebase instead of storing just courseKey1 should I store all the data associated to couseKey1? However, this will cause rooting in firebase because if I structure this way now in my courses root when I say the intructors key instead of just saving the key I would save everything which is just another level deeper firebase goes.
This is kind of an indirect answer:
Denormalizing data is a good thing but in same cases it may not be necessary.
For example in this case a student wants to know his courses, so you know the direct path to the student; users/uid_0 and then maybe a query for the semester you are interested in.
Here's a structure that goes with your courses and instructors
This really isn't very deep since once you read in the user node, you have specific paths to the other data you need: /courses/courseKey1/instructors for example, then followed by instructors/instructor1/name.
Where you get into trouble is if you DON'T know the direct path to the data and have to pile up queries on queries - that's where denormalizing is most effective. Also, queries have lot of overhead vs just observing a node at a path you know.