'Mongoose calculating average from another collection

I am new to MongoDB/Mongoose. I am trying to do a search based on a key string for a 'Resource' which will return a list of resources based on average of ratings for that resource. I am having a hard time calculating and returning the average. This is my schema.

Resource Schema:


const ResourceSchema = mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  type: {
    type: String,
    required: true,
  },
  url: {
    type: String,
    required: true,
  },

  createdDate: {
    type: Date,
    default: Date.now,
  },
});

module.exports = mongoose.model("Resource", ResourceSchema);

Rating Schema:


const RatingSchema = mongoose.Schema({
  resourceId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "Resource",
  },

  createdDate: {
    type: Date,
    default: Date.now,
  },
  rating: {
    type: Number,
    required: true,
    min: 1,
    max: 5,
  },
  review: {
    type: String,
    required: true,
  },

});

module.exports = mongoose.model("Rating", RatingSchema);

Each Resource will have multiple Ratings. I am trying to calculate the average of ratings in my list of fetched Resources and add it to the search results. This is what I have for my search:

Resource.find({
    $or: [
      { title: { $regex: req.params.searchStr.toLowerCase(), $options: "i" } },
      { url: { $regex: req.params.searchStr.toLowerCase(), $options: "i" } },
    ],
  })


Solution 1:[1]

Here's one way you could do it.

db.resources.aggregate([
  { // filter resources
    "$match": {
      "title": {
        "$regex": "passenger",
        "$options": "i"
      },
      "url": {
        "$regex": "https",
        "$options": "i"
      }
    }
  },
  { // get ratings for resource
    "$lookup": {
      "from": "ratings",
      "localField": "_id",
      "foreignField": "resourceId",
      "pipeline": [
        {
          "$project": {
            "_id": 0,
            "rating": 1
          }
        }
      ],
      "as": "ratings"
    }
  },
  { // calculate average
    "$set": {
      "avgRating": { "$avg": "$ratings.rating" }
    }
  },
  { // don't need ratings array anymore
    "$unset": "ratings"
  }
])

Try it on mongoplayground.net.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 rickhg12hs