I've tried to use virtual populate between two models I created: in this case to get all the reviews with the tour id and show them with the tour. (when using query findById() to show only this tour)
my virtual is set to true in the Schema (I've tried to set them to true after using the virtual populate but it doesn't work - by this soultion)
after checking the mongoose documentation its seems to be right but it doesn't work.
my tourSchema:
const tourSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'A tour must have a name'], //validator
unique: true,
trim: true,
maxlength: [40, 'A tour name must have less or equal then 40 characters'],
minlength: [10, 'A tour name must have at least 10 character']
//validate: [validator.isAlpha, 'A tour name must have only alphabetic characters']
},
etc...
etc...
etc...
//guides: Array --- array of user id's || embedding
guides: [
//Reference to the user data model without saving the guides in the tour data model
//Child referencing
{
type: mongoose.Schema.ObjectId,
ref: 'User'
}
]
},
{
//passing options, getting the virual properties to the document/object
toJSON: { virtuals: true },
toObject: { virtuals: true }
}
);
//Define virtual properties
tourSchema.virtual('durationWeeks').get(function () {
console.log('Virtual 1');
//using function declaration => using this keyword
return this.duration / 7;
});
//Virtual populate
tourSchema.virtual('reviews', {
ref: 'review',
localField: '_id', // Find tour where `localField`
foreignField: 'tour', // is equal to `foreignField`
//look for the _id of the tour in the tour field in review
});
my reviewSchema: ** I used in the review schema in for the tour and user populate for the tour id **
const reviewSchema = new mongoose.Schema({
review: {
type: String,
required: [true, 'Review can not be empty!']
},
rating: {
type: Number,
min: 1,
max: 5
},
createdAt: {
type: Date,
default: Date.now(),
},
tour: [
{
type: mongoose.Schema.ObjectId,
ref: 'Tour',
required: [true, 'Review must be belong to a tour.']
}
],
user: [
{
type: mongoose.Schema.ObjectId,
ref: 'User',
required: [true, 'Review must be belong to a user.']
}
]
},
{
//passing options, getting the virual properties to the document/object
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
//Query middleware
reviewSchema.pre(/^find/, function (next) {
this.populate({
path: 'tour',
select: 'name'
})
.populate({
path: 'user',
select: 'name'
});
next();
});
My output: get all reviews (review model data):
{
"status": "success",
"data": {
"review": [
{
"_id": "5f6ba5b45624454efca7e0b1",
"review": "What an amzing tour",
"tour": {
"guides": [],
"_id": "5c88fa8cf4afda39709c2955",
"name": "The Sea Explorer",
"durationWeeks": null,
"id": "5c88fa8cf4afda39709c2955"
},
"user": {
"_id": "5f69f736e6eb324decbc3a52",
"name": "Liav"
},
"createdAt": "2020-09-23T19:44:52.519Z",
"id": "5f6ba5b45624454efca7e0b1"
}
]
}
}
and the get tour by id:
{
"status": "success",
"data": {
"tour": {
"startLocation": {
"type": "Point",
"coordinates": [
-80.185942,
25.774772
],
"description": "Miami, USA",
"address": "301 Biscayne Blvd, Miami, FL 33132, USA"
},
"ratingsAverage": 4.8,
"ratingsQuantaity": 0,
"images": [
"tour-2-1.jpg",
"tour-2-2.jpg",
"tour-2-3.jpg"
],
"startDates": [
"2021-06-19T09:00:00.000Z",
"2021-07-20T09:00:00.000Z",
"2021-08-18T09:00:00.000Z"
],
"secretTour": false,
"guides": [],
"_id": "5c88fa8cf4afda39709c2955",
.
.
.
.
"slug": "the-sea-explorer",
"__v": 0,
"durationWeeks": 1,
"id": "5c88fa8cf4afda39709c2955"
}
}
}
as you can see the review has the tour as an arr and the id is inside the arr of the tour is there an option that the populate is not targeting the right field?