Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle empty arrays in Firebase?

Say person can have multiple cars, and car can have multiple accidents. So we could have:

# Person with no cars
person:
  name: "Misha"
  cars: []

# Person with free-accident car
person:
  name "Arlen"
  cars:
    0:
      name: "Toyota"
      accidents: []

Firebase stores these people as:

person:
  name: "Misha"

and

person:
  name "Arlen"
  cars:
    0:
      name: "Toyota"

So in JavaScript I have to do following to restore the empty arrays: (CoffeeScript)

if person.cars?
  for car in person.cars
    car.accidents = [] unless car.accidents?
else
  person.cars = []

Is there a better way to handle empty arrays in Firebase without writing this needless JavaScript code?

like image 418
Misha Moroshko Avatar asked Mar 14 '13 11:03

Misha Moroshko


2 Answers

I think that, if I understand the core question, the short answer is that there is no way to force an empty array into Firebase. However, there are some paradigms that might work better than what you have above.

Keep in mind that Firebase is a real-time environment. The number of cars and accidents can (and will) change at any time. It's best to treat everything as new data arriving in real time and avoid even thinking about exists or doesn't exist.

// fetch all the people in real-time
rootRef.child('people').on('child_added', function(personSnapshot) {

   // monitor their cars
   personSnapshot.ref().child('cars', 'child_added', function(carSnapshot) {

       // monitor accidents
       carSnapshot.ref().child('accidents', 'child_added', function(accidentSnapshot) {
           // here is where you invoke your code related to accidents
       });
   });
});

Note how there is no need for if exists/unless type logic. Note that you would probably also want to monitor child_removed on cars and people and call ref.off() to stop listening to specific children.

If for some reason you want to stick with the static model, then forEach will become your friend:

// fetch all the people as one object, asynchronously
// this won't work well with many thousands of records
rootRef.child('people').once('value', function(everyoneSnap) {

   // get each user (this is synchronous!)
   everyoneSnap.forEach(function(personSnap) {

        // get all cars (this is asynchronous)
        personSnap.ref().child('cars').once('value', function(allCars) {

           // iterate cars (this is synchronous)
           allCars.forEach(function(carSnap) { /* and so on */ });

        });

   });   
});

Note how, even with forEach, there is no need for "exists or unless" sort of logic.

like image 163
Kato Avatar answered Oct 28 '22 20:10

Kato


I usually use the DataSnapshot function numChildren() to see if it's empty of not, like this

var fire = new Firebase("https://example.firebaseio.com/");
fire.once('value', function(data){if (data.numChildren() > 0){ /*Do something*/ });
like image 21
João Marcelo Brito Avatar answered Oct 28 '22 18:10

João Marcelo Brito