DEV Community

Sakibul Anwar
Sakibul Anwar

Posted on

Mongoose multiple references for one property (dynamic references via refPath)

Let's assume we have two models
1.Mobile
2.Laptop

We want to add review feature for customers in our application. For one review model there will be multiple references.
This process is bit complicated, but we will go through this.

  1. Create Review model

const mongoose = require('mongoose');
const reviewSchema = new mongoose.Schema(
  {
    review: {
      type: String,
      required: [true, 'Review is required'], //Review: Good product
      min: 3,
      max: 200,
    },
    rating: {
      type: Number,
      required: [true, 'Review is required'], //Rating: 5
      min: 1,
      max: 5,
      default: 4,
    },
    product: {
      type: mongoose.Schema.Types.ObjectId,
      refPath: 'onModel', // product => mobile,laptop
      required: [true, 'Review must belong to a product'],
    },
    onModel: {
      type: String,
      required: true,
      enum: ['Laptop', 'Mobile'],
    },
    user: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: [true, 'Review must belong to a user'], //user who reviewed your product
    },
    createdAt: {
      type: Date,
      default: Date.now(),
    },
  },
  {
    toJSON: { virtuals: true },
    toObject: { virtuals: true }, //for virtual property. 
  }
);

reviewSchema.pre(/^find/, function (next) {
  this.populate({ path: 'product', select: 'name  image slug' }); //this will populate the product details in the review route for all the find operations. example: api/review
  this.populate({
    path: 'user',
    select: 'name image',
  }); //this will populate the user details in the review route
  next();
});

const Review = mongoose.model('Review', reviewSchema);

module.exports = Review;

Enter fullscreen mode Exit fullscreen mode
  1. Create Review middleware for post request
exports.createReview=async (req,res,next)=>{
try{
    const { review,rating,user,onModel,product} = req.body;
 await Review.create({review,rating,user,onModel,product})

// logic
}catch(err){
//error logic
}
}
Enter fullscreen mode Exit fullscreen mode

Image description

  1. Virtual Populate in Mobile model
 const mobileSchema = new mongoose.Schema(
  {
//logic
  },
  {
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

//virtual populating
mobileSchema.virtual('reviews', {
  ref: 'Review', //referencing review model
  localField: '_id',  //mobile object id
  foreignField: 'product', //Review model field for mobile object id
});

const Mobile = mongoose.model('Mobile', mobileSchema);
module.exports = Mobile;

Enter fullscreen mode Exit fullscreen mode
  1. Populating reviews of Mobile model
exports.getMobileById=async (req,res,next)=>{
try{

const mobile=await Mobile.findById(req.params.id).populate({ path: 'reviews', select: 'review rating user createdAt'});

//other logics

}catch(err){
//error logic
}
}  
Enter fullscreen mode Exit fullscreen mode

Image description

Thank you for reading

Connect With Me : Github LinkedIn

#mongoose #dynamic #reference

Top comments (0)