Mongoose multiple references for one property (dynamic references via refPath)
Published: 2022-07-27 10:30:00

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;

```

2. 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
}
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4ribnla49bdombpq6p5.png)

4. 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;

```

5. 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
}
}  
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ieb4o3tmikbukthhpzc8.png)
 
 
Thank you for reading 

Connect With Me : [Github](https://github.com/Sakib-lite) [LinkedIn](www.linkedin.com/in/sakibul-anwar-5b06ab181)

  #mongoose #dynamic #reference