0

I'm using mongoose in application and I have the following fields in my schema;

const CourseSchema = new mongoose.Schema({
  ...

  feedback: {
    count: {
      type: Number,
      default: 0,
    },
    ratings: {
      clarity: {
        type: Number,
        default: 0,
      },
      engagement: {
        type: Number,
        default: 0,
      },
      completeness: {
        type: Number,
        default: 0,
      }
    }
  }
})

Each time a user submits a feedback, the application performs an incremental average update using the current average and the count value. This means I would have to get the current numbers from the DB, update them with the new numbers and send them back. To do this, I use findById to get the document, get the existing numbers, update with the new values and update them in the DB using updateOne. Is there a way to do this all at once in one single query? I have seen some examples floating around, but they don't seem concrete enough for my use case.

Below is the code I am experimenting with right now. I'm pretty sure its not correct, but it should give an idea of what I'm trying to achieve.

await Course.findById(
  id,
  (error, course) => {
    if (error) res.status(404).send("Course does not exist");

    const { ratings } = req.body;
    const { ratings: currRatings, count } = course.feedback;

    Object.keys(currRatings).forEach(metric => {
      /* Incremental averaging
      newAverage = oldAverage + (newValue - oldAverage) / newSampleCount;
      */
      (course.feedback.ratings[metric] =
        course.feedback.ratings[metric] +
        ratings[metric] - course.feedback.ratings[metric]) / (count +
        1);
    });
    // increment the number of feedback by 1 for each feedback we receive
    course.feedback.count += 1;
  },
);
Saneyar
  • 63
  • 6
  • You can try using the Updates with Aggregation Pipeline feature - this will allow the update to be a single operation (instead of the find, loop, update). – prasad_ Oct 11 '21 at 02:52

0 Answers0