20

I tried using presence to make it display the total connected users in an element. I can't really figure out how to make it work.

I also tried doing the following:

    var dataUlist = new Firebase('https://<url>.firebaseio.com/.info/connected');
    dataUlist.on('value', function(snap) {
        console.log(snap);
    });

To tried to see if I could find anything useful in there, but I couldn't figure out how the data works.

Is there any way to accomplice what I am after? Fetch the total number of connected users and then echo it out in the console or to an element?

Bella
  • 104
  • 17
MrE
  • 1,124
  • 3
  • 14
  • 28

2 Answers2

34

.info/connected will only return information about whether the current client is connected or not. In order to maintain a presence count, you'll need to create a counter by storing presence information for each user and utilizing setOnDisconnect(). For example:

var listRef = new Firebase("https://<url>.firebaseio.com/presence/");
var userRef = listRef.push();

// Add ourselves to presence list when online.
var presenceRef = new Firebase("https://<url>.firebaseio.com/.info/connected");
presenceRef.on("value", function(snap) {
  if (snap.val()) {
    // Remove ourselves when we disconnect.
    userRef.onDisconnect().remove();

    userRef.set(true);
  }
});

// Number of online users is the number of objects in the presence list.
listRef.on("value", function(snap) {
  console.log("# of online users = " + snap.numChildren());
});    
Dvir Berebi
  • 1,406
  • 14
  • 25
Anant
  • 7,408
  • 1
  • 30
  • 30
  • 2
    Happy to help! My colleague pointed out two corrections: 1. The `onDisconnect()` call should be inside the `.info/connected` callback because we have to call it again when we reconnect. 2. We have a handy function called `numChildren()` to return the number of keys in an object! I've updated the snippet above to reflect this. – Anant Apr 13 '13 at 00:08
  • Awesome guys, thank you soo much for the help, I am playing about with it now already - works a treat! – MrE Apr 13 '13 at 00:12
  • 2
    This seems a bit unscalable. Is there a way to just get an integer back? – Harry Jun 30 '13 at 01:22
  • Can you use .info/connected for child paths in order to get the number of users in a specific chat room? I.e. (https://.firebaseio.com//.info/connected) ?? – JoshSGman May 29 '14 at 15:46
  • 1
    No, .info/connected is only a valid path from the root. – Anant May 29 '14 at 20:13
  • 1
    @Anant -- it looks like your answer introduces a potential race condition. Luckily, an article you wrote helped point this out to me so I could remind you about it :-). In your very own words, "The onDisconnect() call is before the call to set() itself. This is to avoid a race condition where you set the user’s presence to true and the client disconnects before the onDisconnect() operation takes effect, leaving a ghost user". (from https://www.firebase.com/blog/2013-06-17-howto-build-a-presence-system.html). – MandM Apr 14 '15 at 15:38
  • The problem is that in order for this to work one must pull down the ENTIRE list. So if you have a a user list of 10k, you'll need to pull down that entire list of 10k users which equals roughly 250kb. The only way I can think of to do this in a way that scales is to pull this list down on a server you control, and then deliver that number to the client. – Tyler Biscoe Jun 19 '16 at 04:54
  • I have wrote a module based on this idea for my own need. But this may help many others. Please check - https://gist.github.com/ajaxray/17d6ec5107d2f816cc8a284ce4d7242e – Anis Jul 11 '16 at 20:10
1

Here is the the code from Anant formatted for Android

public void getDbCount() {

    Firebase listRef = new Firebase("https://<your-firebase-database>.firebaseio.com/presence/");
    final Firebase userRef = listRef.push();

    // Add ourselves to presence list when online.
    Firebase presenceRef = new Firebase("https://<your-firebase-database>.firebaseio.com/.info/connected");

    ValueEventListener myPresence = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            // Remove ourselves when we disconnect.
            userRef.onDisconnect().removeValue();
            userRef.setValue(true);
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Log.e("DBCount", "The read failed: " + firebaseError.getMessage());
        }
    };

    presenceRef.addValueEventListener(myPresence);

    // Number of online users is the number of objects in the presence list.
    ValueEventListener myList = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            // Remove ourselves when we disconnect.
            Log.i("DBCount", "# of online users = " + String.valueOf(snapshot.getChildrenCount()));
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Log.e("DBCount", "The read failed: " + firebaseError.getMessage());
        }
    };

    listRef.addValueEventListener(myList);
}
Tony C
  • 21
  • 3
  • Please elaborate on how this code answers the question. – JAL Apr 08 '16 at 02:50
  • You are creating a section in your database to track presence. When added and executed it will push a key representing the current user onto the presence child. Firebase userRef = listRef.push(); When that user is disconnected, (Firebase object presenceRef) they will be removed from the list. userRef.onDisconnect().removeValue(); This code will display in the log the current number of users currently connected to the system, assuming everyone on the system executed this code. See https://www.firebase.com/blog/2013-06-17-howto-build-a-presence-system.html for a more robust explanation. – Tony C Apr 22 '16 at 02:44