NoSQL Firebase denormalization

246 views Asked by At

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.

1

There are 1 answers

0
Jay On

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

users
   uid_0
    schedules
      -Yiaiajsdaoiojasd
         semester: 1
         courses
            course1: true
            course3: true
      -Jyuhus99jsijskkss
         semester: 2
         courses
            course2: true
            course4: true
   uid_1
    schedules
      -Yjs909k0s0s0ks0s
         semester: 1
         courses
            course1: true
            course3: true
      -Jyuhus99jsijskkss
         semester: 2
         courses
            course2: true
            course4: true

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.