Creating a Leaderboard Using Data Retrieved from Firebase

Hi all,

I was on a week or two ago asking about data in Firebase. Thanks to the help on this forum and a lot of google, I was able to get my database set up and I am now retrieving data from the Firebase database.

My new question is, how do I retrieve this data and then use the data to build a leaderboard. Everytime a score is added/updated, I want to loop through this data, find everyone who has a score (the count variable) and then print out the username and score. I have tried a number of solutions and currently the best I can do is adding every user with a score to the div everytime a score is added/updated. But I only want one entry per person and I want the entry to update each time the score changes.

Here is what my code looks like so far:

<div class="leaderboard">
  <p>Leaderboard</p>
  <ul id="leaderboard">
  </ul>
</div>

<script>
let leadsRef = database.ref('users');
let leaderboard = document.querySelector('#leaderboard');
let array = [];

// I get the data using this function
leadsRef.on('value', function (data) {
  var childData = childSnapshot.val();
  
  // childData is now a bunch of typeof objects that looks like this:
  // { count: 0, username: 'John' }
  // now, I try to loop through each of these objects and add them to the leaderboard

  if (childData.count >= 0) {
    let li = document.createElement('li');
    let text = document.createTextNode(childData.username + ' has a score of ' + childData.count);
    li.appendChild(text);
    leaderboard.appendChild(li);
  }

  // this leads to every user and score being printed over and over again whenever the count increases for a user
  // so I tried adding leaderboard.innerHTML = ''; before I create the li, and that doesn't work either
}

</script>

Does anyone have any ideas?

Thanks!

1 Like

So, I get really confused by this, but I don’t think that childData is an array. I think it just returns an object for each? When I console.log(typeof childData) it returns object and when I console.log(childData) it returns {count: whatever, username: whatever}.

Does that help at all?

There also could be two or more objects with the same username, although in the very limited demonstration I’m doing, there will not be.

Thank you so much for your help. I have been able to implement this and it is working better than before. I think I’m not understanding the part about how to update the data. Here is the code that I’ve wrote based on your response. The current result is: when the player first starts the game, the leaderboard shows all of the people who’ve scored in the game before, which is what I want. But, when the new player scores, it just adds all of the players and scores over and over again.

const userCounts = {};

leadsRef.on('value', function (data) {
            
            data.forEach(function (childSnapshot, index) {
                var childData = childSnapshot.val();
                
                if (childData.count > 0) {
                    if (userCounts.hasOwnProperty(childData.username)) {
                        //
                    } else {
                        userCounts[childData.username] = childData.count;
                    }
                }
                          
            }); // this is the end of the foreach
            
            Object.keys(userCounts).forEach(function(key) {
                console.log(key, userCounts[key]);
                let li = document.createElement('li');
                li.id = key.toLowerCase();
                li.innerHTML = key + ' scored ' + userCounts[key];
                leaderboard.appendChild(li);
            });
        });

Hi!

Here is what I ended up doing.

 leadsRef.on('value', function (data) {
            
            data.forEach(function (childSnapshot, index) {
                var childData = childSnapshot.val();
                
                if (childData.count > 0) {
                    if (userCounts.hasOwnProperty(childData.username)) {
                        newId = childData.username.toLowerCase();
                        let userCountHolder = document.getElementById(newId);
                        userCountHolder.innerHTML = childData.count;
                        console.log(userCountHolder);
                    } else {
                        userCounts[childData.username] = childData.count;
                        console.log(userCounts);
                        let li = document.createElement('li');
                        newId = childData.username.toLowerCase();
                        li.innerHTML = childData.username + ' scored ' + '<span id="' + newId + '">' + childData.count + '</span>';
                        leaderboard.appendChild(li);
                    }
                }
                
            }); // this is the end of the foreach
            
        });

It works right now but the method that you’ve suggested seems cleaner.

Thank you so much for your help, I really appreciate it!

I’m honestly not sure. When I try typeof data is returns object?

It returned false when I tried that.

It returns false in both spots.

leadsRef.on('value', function (data) {
            console.log(Array.isArray(data));
            
            data.forEach(function (childSnapshot, index) {
                var childData = childSnapshot.val();
                console.log('data ', Array.isArray(data));

It returns:

{“Aimeiqn2fr4xKUZSM463”:{“count”:2,“username”:“J”},“HIXvoUgliXS0HFKtHhcuM9sAjOD2”:{“count”:9,“username”:“A”},“J0jmvyamugMBZt9QDjj2”:{“count”:9,“username”:“K”},“LZb9WKKokyyjiNbwUup2”:{“count”:0,“username”:“J”},“OdpkjRt2xdhneJICe5G2”:{“count”:9,“username”:“An”},“a70hJDZ91etlJr6r5lB3”:{“count”:4,“username”:“R”}}

{"Aimeiqn2fr4xKUZSM463":{"count":2,"username":"J"},"HIXvoUgliXS0HFKtHhcuM9sAjOD2":{"count":9,"username":"A"},"J0jmvyamugMBZt9QDjj2":{"count":9,"username":"K"},"LZb9WKKokyyjiNbwUup2":{"count":0,"username":"J"},"OdpkjRt2xdhneJICe5G2":{"count":9,"username":"An"},"a70hJDZ91etlJr6r5lB3":{"count":4,"username":"R"}}

EDIT: I don’t know if this is useful at all, but for whatever reason, the index parameter in the forEach always returns undefined, when I would normally expect it to return the index number.