0

This question has been asked before but I didn't quite understand the answer.

I need to calculate the average of an array of data from Firebase, so I have two steps.

  1. Retrieve all the data
  2. Determine how many entries there are in that same data
  3. Calculate the average

My code:

myDataRef.orderByChild("time").startAt(time-180000).endAt(time).on("child_added", function(snapshot) {
    votes = snapshot.val().vote;
    //console.log("Vote value:" + votes)
});

myDataRef.orderByChild("time").startAt(time-180000).endAt(time).on("value", function(snapshot) {
    numberOfVotes = snapshot.numChildren();
    //console.log("Number of Votes:" + numberOfVotes)
});

function calculateAverage(numberOfVotes, votes) {
    return eval(votes.join('+')) / numberOfVotes;
}

console.log(calculateAverage)

I think I'm misinterpreting something super basic because I can't figure out how to get the data "out" of the Firebase query and into a function. What am I missing?

Community
  • 1
  • 1
jake-sl
  • 1
  • 2

2 Answers2

1

Firebase loads data asynchronously. You can only determine you average once the data the query has been loaded completely.

One way that comes to mind is:

myDataRef.orderByChild("time").startAt(time-180000).endAt(time).on("value", function(snapshot) {
    var voteCount = snapshot.numChildren();
    var total = 0;
    snapshot.forEach(function(voteSnapshot) {
        total += voteSnapshot.val().vote;
    });
    console.log("Average=" + total / voteCount);
});

Some things of note:

  • I use a single value event. Not sure why you were using both value and child_added, but it only seemed to complicate things.

It is also possible to keep a running average while listening to child_ events, but you'll have to listen to all of them.

var total = 0, 
    voteCount = 0;
    query = myDataRef.orderByChild("time").startAt(time-180000).endAt(time);
query.on("child_added", function(snapshot) {
    voteCount += 1;
    total += snapshot.val().vote;
    console.log("Running average: "+total/voteCount);
});
query.on("child_removed", function(snapshot) {
    voteCount -= 1;
    total -= snapshot.val().vote;
    console.log("Running average: "+total/voteCount);
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
0

I was doing the same thing you are trying to do, but with user ratings. I changed the terms "ratings" to "votes" for you and added "myDataRef." This worked for me:

Controller:

myDataRef.getVotesforUser(uid).then(function(votes) {

for(var i = 0; i < votes.length; i++) {
  votes[i].type? $scope.userVote.push(votes[i])  : $scope.userVote.push(votes[i])
}

$scope.numVote = $scope.userVote.length;


$scope.total = 0;
votes.forEach(function(votes) {
  $scope.total += votes.vote;
});
console.log("average", + $scope.total);
console.log("average", + $scope.total / $scope.numVote);

});

Service:

    getVotesforUser: function(uid) {
    var defer = $q.defer();

    $firebaseArray(ref.child('user_votes').child(uid))
      .$loaded()
      .then(function(votes) {
        defer.resolve(votes);
      }, function(err) {
        defer.reject();
      });


    return defer.promise;
  },
MMM
  • 1
  • 3