I have the Express application example from Getting MEAN book. I am connecting to Mongodb with Mongoose. Here's the document
{
"_id": {
"$oid": "65537eb149dd64103a4b7950"
},
"name": "Starcups",
"address": "125 High Street, Reading, RG6 1PS",
"rating": 3,
"facilities": [
"Hot drinks",
"Food",
"Premium wifi"
],
"coords": [
-0.9690884,
51.455041
],
"openingTimes": [
{
"days": "Monday - Friday",
"opening": "7:00am",
"closing": "7:00pm",
"closed": false
},
{
"days": "Saturday",
"opening": "8:00am",
"closing": "5:00pm",
"closed": false
},
{
"days": "Sunday",
"closed": true
}
],
"reviews": [
{
"author": "Lekan Yusuf",
"id": {
"$oid": "6560c0dfadc556388f6b8e93"
},
"rating": 4,
"timestamp": {
"$date": "1992-06-11T23:00:00Z"
},
"reviewText": "Good wifi, moderate coffee"
},
{
"author": "Lekan Yusuf",
"id": {
"$oid": "6563c6c0d8b148207dcc9817"
},
"rating": 4,
"timestamp": {
"$date": "1992-06-11T23:00:00Z"
},
"reviewText": "Good wifi, moderate coffee"
}
]
}
I have this routes:
var express = require('express');
var router = express.Router();
var ctrlReviews =require('../controllers/reviews');
//reviews routes
router.get('/locations/:locationid/reviews/:reviewid', ctrlReviews.reviewsReadOne);
router.post('locations/:locationid/reviews', ctrlReviews.createReview);
router.put('locations/:locationid/reviews/reviewid', ctrlReviews.reviewsUpdateOne);
router.delete('locations/:locationid/reviews/reviewid', ctrlReviews.reviewsDeleteOne);
This is the controller code:
module.exports.reviewsReadOne = function(req, res){
console.log('in ReviewsReadOne');
if(req.params && req.params.locationid && req.params.reviewid){
console.log('locationid: '+ req.query.locationid + ' reviewid: '+ req.query.reviewid);
Loc.findById(req.query.locationid, 'name reviews').exec(
function(err,location){
var response, review;
if(!location){
sendJsonResponse(res, 404, {"message": "locationid not found"});
return;
} else if (err){
sendJsonResponse(res, 404, err);
return;
}
console.log('location just before "if(location.reviews && location.reviews.length >0)"\n' + location);
console.log('\n reviews: '+ location.reviews);
if(location.reviews && location.reviews.length >0){
review = location.reviews.id(req.params.reviewid);
if(!review){
sendJsonResponse(res, 400, {"message":"Review id not found"});
} else {
console.log('review ' + review)
response ={
location:{
name: location.name,
id: req.query.id
},
review:review
};
sendJsonResponse(res, 200, response);
}
} else {
sendJsonResponse(res, 400, {message:"Not found, locationid and reviewid are both required"});
}
}
);
} else{
sendJsonResponse(res, 400, {"message": "No location id and or review id"});
return;
}
}
When I test the API from Postman with existing locationid and reviewid, it gives:
{
"message": "Not found, locationid and reviewid are both required"
}
VSCode terminal gives the following output:
in ReviewsReadOne
locationid: 65538583fc3b3ac2c0b83a8d reviewid: 6563c74141216ec9d9ec7c38
location just before "if(location.reviews && location.reviews.length >0)"
{
_id: new ObjectId("65538583fc3b3ac2c0b83a8d"),
name: 'Starfi',
reviews: [
{
author: 'Subomi ogunderu',
id: new ObjectId("6563c74141216ec9d9ec7c38"),
rating: 3,
timestamp: 1995-08-11T23:00:00.000Z,
reviewText: 'Excellent wifi and the food is great'
}
]
}
reviews: undefined
GET /api/locations/locationid/reviews/reviewid?locationid=65538583fc3b3ac2c0b83a8d&reviewid=6563c74141216ec9d9ec7c38 400 566.482 ms - 66
Obviously, the location document is retrieved but the test,
if(location.reviews && location.reviews.length >0)
fails and that seems to be the reason I get
reviews: undefined
in the terminal.
Pls why is reviews undefined and how do I solve this.
On this line:
You seem to be trying to use
id()as if it was a method of thelocation.reviewsarray. Unfortunately, mongoose if not designed that way aslocation.reviewsis of typeMongooseArraywhich has a limited number of methods.Thankfully, mongodb has a good selection of operators that you can use to find and select specific properties of documents which will make your code much easier to read. For example, the
$elemMatchoperator can allow you to match an element from an array and if used in combination with the$positional operator means you can chose to just project that element.You can use this code which adopts a modern
async/awaitpattern utilisingtry/catchblocks for cleaner error handling: