Reputation: 566
I have a project where I'm using the MERN stack along with Redux.
When I'm fetching normal data with a get
request, everything works perfectly after a clean page refresh because I can populate the query with referenced data, but when I'm saving for example new data, in the response json
I'm only receiving the raw data of ObjectID
and not the referenced data with it.
I believe I will need to populate the saved response with a new query or something similar to .populate
in order to get the referenced data but I have no idea to do so.
I already tried something I've read here such as execPopulate
on save()
but didn't work.
Example of response JSON with post
request :
{
"suggestion": "61cb83b1e7a2d3469d2adc9e",
"user": "61b4a9253f40b9c22969d11f",
"content": "testing content",
"rating": 3,
"spoiler": false,
"_id": "61d7df8c5883e282879c6fb9",
"date": "2022-01-07T06:37:00.196Z",
"upvotes": [],
"__v": 0
}
Example of response with get
request that I would want to receive in save
too, notice the fields suggestion
& user
are populated :
{
"_id": "61d7df8c5883e282879c6fb9",
"suggestion": {
"_id": "61cb83b1e7a2d3469d2adc9e",
"title": "Beyond",
"suggestion_type": "Book",
"image": "91b2d138-883a-4fab-8e0c-a554dd466349.png",
"token": "LSSRuE"
},
"user": {
"_id": "61b4a9253f40b9c22969d11f",
"username": "test_user",
"avatar": "https://i.pinimg.com/2349087qsbjkqsbd.jpg"
},
"content": "Testing content",
"rating": 3,
"spoiler": false,
"date": "2022-01-07T06:37:00.196Z",
"__v": 0
}
Save route :
router.post(
'/:token/reviews',
[auth, [check('rating', 'Rating is required').not().isEmpty()]],
async (req, res) => {
try {
const suggestion = await Suggestion.findOne({ token: req.params.token });
const review = await Review.find({
suggestion: suggestion.id,
});
const newReview = new Review({
content: req.body.content,
rating: req.body.rating,
spoiler: req.body.spoiler,
user: req.user.id,
suggestion: suggestion.id,
});
await newReview.save();
res.json(newReview);
} catch (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
}
);
Get route :
router.get('/:token/reviews/', auth, async (req, res) => {
try {
const suggestion = await Suggestion.findOne({
token: req.params.token,
});
const review = await Review.find({
suggestion: suggestion.id,
})
.populate('user', ['avatar', 'username', 'id'])
.populate('suggestion', [
'id',
'token',
'title',
'image',
'suggestion_type',
]);
if (!review) {
res
.status(404)
.json({ msg: 'No reviews found for the specified suggestion' });
}
res.json(review);
} catch (error) {
console.error(error.message);
if (error.kind === 'ObjectId') {
res.status(404).json({ msg: 'Review not found' });
}
res.status(500).send('Server Error');
}
});
Reviews model :
const mongoose = require('mongoose');
const ReviewSchema = new mongoose.Schema({
suggestion: { type: mongoose.Schema.Types.ObjectId, ref: 'suggestion' },
user: { type: mongoose.Schema.Types.ObjectId, ref: 'user' },
date: { type: Date, default: Date.now },
content: {
type: String,
},
rating: {
type: Number,
},
spoiler: { type: Boolean, default: 0 },
});
module.exports = mongoose.model('review', ReviewSchema);
Upvotes: 2
Views: 3826
Reputation: 1
You can do this by chaining populate
after findOne
using dot notation.
ex.
const person = await Person.findOne({
name: 'Ian Fleming'
}).populate('stories');
bonus: for field selection, you can use mongo syntax.
ex.
populate('stories', { title: 1, author: 1 });
will return an object populated with those fields only including _id.
Refer to mongodb docs for more
Upvotes: 0
Reputation: 566
Solved.
I added this line await newReview.populate('user');
after await newReview.save();
From the official documentation : https://mongoosejs.com/docs/populate.html#populate_an_existing_mongoose_document
Populating an existing document
If you have an existing mongoose document and want to populate some of its paths, you can use the Document#populate() method.
const person = await Person.findOne({ name: 'Ian Fleming' });
person.populated('stories'); // null
// Call the `populate()` method on a document to populate a path.
await person.populate('stories');
person.populated('stories'); // Array of ObjectIds
person.stories[0].name; // 'Casino Royale'
Upvotes: 5