ethanfox27
ethanfox27

Reputation: 897

Taking the average of a data set in Firebase Database - Cloud Functions for Firebase

I am creating an app that allows users to rate a business from 1 to 5. I am trying to find the average of the ratings to use in my app. So far I am currently only able to see the count with this code.

I am struggling to figure out how to read the all of the rating objects (randomValue: Int). I was thinking it would be best to store them in an array. I am very new to Node so forgive me.

I cannot find anything in the Cloud Functions for Firebase docs about this.

The ratings are stored as follows:enter image description here

My Code:

exports.scoreOneAverage = functions.database.ref('/ratings_average/{business_uid}/Score_1/{random}')
.onWrite(event => {
  const collectionRef = event.data.ref.parent;
  const countRef = collectionRef.parent.child('count');

  // Return the promise from countRef.transaction() so our function
  // waits for this async event to complete before it exits.
  return countRef.transaction(current => {
    if (event.data.exists() && !event.data.previous.exists()) {
      return (current || 0) + 1;

    }
    else if (!event.data.exists() && event.data.previous.exists()) {
      return (current || 0) - 1;
    }
  }).then(() => {
    console.log('Counter updated.');
    List ratings = event.data.val();
    count = countRef.event.data.val();
    if( ratings === null ) {
          console.log('No ratings');
       }
       else {
          console.log("The average score is:" + count + ratings );
       }


  });
});

Upvotes: 0

Views: 947

Answers (1)

Mike Bifulco
Mike Bifulco

Reputation: 88

The cloud function event you're triggering should be adjusted slightly to make this work. B

From the docs on cloud functions

Path specifications match all writes that touch a path, including writes that happen anywhere below it. If you set the path for your function as /foo/bar, it matches writes at both of these locations:

/foo/bar
/foo/bar/baz/really/deep/path

So basically, the best way to approach this is likely to listen to writes on this path: /ratings_average/{business_uid}/Score_1

You'll also probably want to take advantage of the fantastic lodash library - it has functions that will help you iterate over a javascript Object. Because your firebase database is structured as a series of nested json (with no notion of arrays), you need to traverse over objects to iterate on any collection of data, like the values at Score_1. Below, I'm using the handy lodash .forOwn() function, and lodash .size() to get the number of scores we're taking an average on

Roughly coded out, an average function would look like this:

// at the top of your file,
import _ from 'lodash';
exports.scoreOneAverage = functions.database.ref('/ratings_average/{business_uid}/Score_1')
  .onWrite(event => {
    const scores = event.data.val();
    const avgSum = 0;
    _.forOwn(scores, (scoreKey, scoreValue) => {
      avgSum += scoreValue;
    });
    const avg = avgSum / _.size(scores); // this is your average! Do with it what you like
  });

Upvotes: 2

Related Questions