Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper use of hasChild() and forEach() from a reference in Firebase?

Tags:

firebase

With my limited understanding, and SQL background, I'm not quite groking the usage of hasChild() and forEach(); they feel like they belong on the reference and not the snapshot.

(I'll use hasChild() for the rest of the discussion, but the concepts are interchangeable.)

Here's my reasoning:

  1. I have a Firebase path called for a users table, say appname/users
  2. I want to see if a user (Fred) exists
  3. I obtain a reference: var users = new Firebase('appname/users')

But I can't determine if a child exists from here. So here is what I have now:

users.child('Fred').once('value', function(snapshot) {
   /** waits around forever if Fred doesn't exist */
});

But that doesn't quite work. So now I must get the value of users (which feels a bit counter-intuitive, since I'm not interested in users) with something like this:

var users = new Firebase('http://.../appname/users');
users.once('value', function(snapshot) { 
      snapshot.childExists('Fred', function(exists) { 
         /* do something here*/ 
      }); 
   });

I don't imagine I incur a large overhead by fetching appname/users, based on the docs, but this feels like an unsightly bit of code if I just want to determine if the key 'Fred' exists.

I'd like to see something like:

var users = new Firebase('http://.../appname/users');
users.hasChild('Fred', function(exists[, snapshotOfFred]) { 
   /* do something here*/ 
});

Is there a better approach to using forEach/hasChild? Have I missed any important logical considerations here?

like image 915
Kato Avatar asked Jul 10 '12 19:07

Kato


1 Answers

You were actually on the right track with your first code snippet. .once() will trigger your callback with a snapshot, regardless of whether Fred already exists or not. So you can just do:

users.child('Fred').once('value', function(snapshot) {
   if (snapshot.val() === null) {
       /* There is no user 'Fred'! */
   } else {
       /* User 'Fred' exists.
   }
});

Your second code snippet would actually incur a large overhead, since Firebase would fetch the entire 'users' location from Firebase, which could be quite large if you have 1000s of users! So the first code snippet is definitely the way to go.

The reason that hasChild and forEach are on the DataSnapshot instead of on Firebase is so that they can be synchronous. In our early API testing, we had a mix of synchronous and asynchronous methods available on the Firebase reference, but we found that this was a significant stumbling block for folks (if people see a hasChild method, they'll expect it to return a boolean immediately). So we created .on() and .once() to be the one and only asynchronous callback methods on Firebase. Everything else on a Firebase reference is synchronous (though we sometimes provide optional asynchronous completion callbacks), and everything on a DataSnapshot is 100% synchronous.

So our goal was to make the asynchronous nature of Firebase easier for people to understand and use! But perhaps we haven't succeeded 100%. :-) We'll take your feedback into account when planning future API tweaks. Thanks!

like image 79
Michael Lehenbauer Avatar answered Oct 17 '22 22:10

Michael Lehenbauer