Franchise
Franchise

Reputation: 1241

Calculate sum of object array field

Working on a Node App with Express as the web framework and Mongo as the backend. Currently, I have a Mongoose data schema with players and associated statistics. Here's an anonymized example of the structure:

  name: 'Player Name',
  image: 'image-location',
  position: 'Guard',
  description: 'Player Detail',
  __v: 6,
  weight: 200,
  dob: 1993-08-03T05:00:00.000Z,
  hometown: 'town-name',
  country: 'country-name',
  height_feet: 6,
  height_inches: 4,
  season: [
    {
      year: '2012-2013',
      grade: 'Freshman',
      gp: 18,
      gs: 0,
      mpg: 6.9,
      fg: 0.348,
      tp: 0.278,
      ft: 1,
      rpg: 0.8,
      apg: 1,
      spg: 0.3,
      bpg: 0,
      ppg: 1.4
    },
    {
      year: '2013-2014',
      grade: 'Sophomore',
      gp: 36,
      gs: 7,
      mpg: 20.3,
      fg: 0.432,
      tp: 0.4,
      ft: 0.643,
      rpg: 1.6,
      apg: 1.1,
      spg: 0.2,
      bpg: 0.1,
      ppg: 7.1
    },
    {
      year: '2014-2015',
      grade: 'Junior',
      gp: 34,
      gs: 33,
      mpg: 27.5,
      fg: 0.449,
      tp: 0.391,
      ft: 0.755,
      rpg: 2.9,
      apg: 2,
      spg: 0.8,
      bpg: 0.1,
      ppg: 10.1
    },
    {
      year: '2015-2016',
      grade: 'R. Senior',
      gp: 8,
      gs: 8,
      mpg: 31.6,
      fg: 0.425,
      tp: 0.291,
      ft: 0.6,
      rpg: 2.9,
      apg: 1.9,
      spg: 0.6,
      bpg: 0.3,
      ppg: 12
    },
    {
      year: '2016-2017',
      grade: 'Senior',
      gp: 35,
      gs: 35,
      mpg: 33.3,
      fg: 0.473,
      tp: 0.384,
      ft: 0.795,
      rpg: 4.6,
      apg: 2.7,
      spg: 1.2,
      bpg: 0,
      ppg: 15.1
    }
  ]

}

I'm still fairly new to Mongo and Node as a whole, so pardon the elementary question. How would I be able to calculate the average of a particular statistic for the total number of seasons (e.g. 4 year average of points per game)?

The goal here is to calculate the value and have it available and passed on the GET route for the player page. Here's the route I have for the player page:

router.get("/:id", function(req, res){
    Player.findById(req.params.id).populate("comments").exec(function(err, foundPlayer){
        if(err){
            console.log(err);
        } else {
            console.log(foundPlayer)
            res.render("players/show", {player: foundPlayer});
        }
    });
});

What can I do to both calculate this value and have it available for use on the player page?

Upvotes: 0

Views: 191

Answers (2)

Syed Mishar Newaz
Syed Mishar Newaz

Reputation: 567

You have to iterate over seasons array and find the average. For example:

const { season } = <.........your MongoDB response>
let average = 0;
if(season.length){
    let total = 0
    season.map(({ gp }) => (total += gp))
    average = total / season.length
}

The variable average will give you the answer. I've shown an example to calculate average of gp

Upvotes: 1

Mohammed Yousry
Mohammed Yousry

Reputation: 2184

we can use aggregate pipeline to calculate the average directly within the query

db.collection.aggregate([
  {
    $match: {
      _id: "playerId1" // this needs to be of type ObjectId, it should be something like mongoose.Types.ObjectId(req.params.id) in your case
    }
  },
  {
    $unwind: "$season" // unwind the season array to get a stream of documents, and to be able to calculate the average of ppg
  },
  {
    $group: { // then group them again
      _id: "$_id",
      averagePointsPerGame: {
        $avg: "$season.ppg"
      },
      season: {
        $push: "$season"
      }
    }
  }
])

you can test it here Mongo Playground

hope it helps

Upvotes: 1

Related Questions