0
votes

I just launched a mobile app that uses Firebase as the data store, and I have a RTDB collection that looks like:

classes:{
"-Kv4KCJM4rHbwqF-pMxN":
{
  "added" : 1515114635871,
  "admins" : {
    "wgKCoCZj4IaWuiwGKwygpEZ3sg02" : true
  },
  "allowConversations" : false,
  "grade" : 998,
  "name" : "Some Name",
  "pageContent" : "Possibly VERY LARGE field",
  "school" : "-KufLJxgD8DE2FnutPbs"
},

  "-KvEpubNdVvlnSsKJ4Z9": {
  "added" : 1515114635871,
  "admins" : {
    "wgKCoCZj4IaWuiwGKwygpEZ3sg02" : true
  },
  "allowConversations" : false,
  "grade" : 998,
  "name" : "Name",
  "pageContent" : "Possibly VERY LARGE field",
  "school" : "-KufLJxgD8DE2FnutPbs"
}
...
}

And I need to load this collection for the sole purpose building a list of links in a mobile app. The problem is pageContent turns out to possibly be very large, a few MB, due to base64 images being inline. Ultimately I'll be moving pageContent out into a separate collection, but I need a short term fix, because this is eating up GB of bandwidth from Firebase each day!

To build a list of links, I need the id(key), name, and grade fields only. I'm using angularfire2, so I'm doing this:

getClasses2(): Promise<any> {
let _thee = this;
return new Promise((resolve, reject) => {
  if (Object.keys(_thee._classesData).length > 0) {
    return resolve(_thee._classesData);
  }

  let classList = _thee.afDB.list(`/schools/${this.schoolid}/classes`).valueChanges();

  classList.subscribe(aClass => {
    console.log(aClass);
    aClass.forEach((c: string, i) => {
      _thee._classesData[c].id = c;
      this.afDB
        .object(`/classes/${c}/grade`)
        .valueChanges()
        .subscribe(grade => {
          _thee._classesData[c].grade = grade;
        });
      this.afDB
        .object(`/classes/${c}/name`)
        .valueChanges()
        .subscribe(name => {
          _thee._classesData[c].name = name;
        });
      if (i + 1 === aClass.length) {
        return resolve(_thee._classesData);
      }
    });
  });
});

}

The issue is handling those two Observables inside a promise. Ideally, the observables just do their thing, and update the appropriate objects in _classesData totally asynchronously, and when the for loop finishes, I resolve the promise, and _classesData 'may' still be getting updated by the observables, but that's fine. The trouble is this looks like garbage, is garbage, and even though this is very short term and will be replaced in a few days, I still need to control bandwidth usage by several hundred mobile devices accessing 50-60Mb of data a few hundred times a day.

Is there an elegant way to properly access two properties in an object while staying somewhat synchronized, using AngularFire2 methods?

1
Please excuse the frankenstein variable naming and context handling (_thee), as I've been hacking around on this trying different thingsregretoverflow
I have worked around this by nesting the observables which isn't ideal, but it gets me past this issue while I re-architect the data model.regretoverflow

1 Answers

0
votes

I think that you need to split description information from have data information. For example remove pageContent from classes and create a pageContent document to hold it.

Because when you request /schools/${this.schoolid}/classes you are getting all classes info. And if any change (in any class) you will get the whole data again (not only the changed class or changed value).

Another point is, maybe you should think about decentralize your database. For example you can have a SchoolName inside your classes instead of just "school" : "-KufLJxgD8DE2FnutPbs".

One last ideia, you can think about use Firebase once(), or Observable ...take(1).subscribe().