5

Hi I'm trying to create a new subdocument via mongoose, but i'm getting the following messages when I execute the POST method in Postman:

{
  "message": "Location validation failed",
  "name": "ValidationError",
  "errors": {
    "reviews.1.reviewText": {
      "message": "Path `reviewText` is required.",
      "name": "ValidatorError",
      "properties": {
        "type": "required",
        "message": "Path `{PATH}` is required.",
        "path": "reviewText"
      },
      "kind": "required",
      "path": "reviewText"
    },
    "reviews.1.rating": {
      "message": "Path `rating` is required.",
      "name": "ValidatorError",
      "properties": {
        "type": "required",
        "message": "Path `{PATH}` is required.",
        "path": "rating"
      },
      "kind": "required",
      "path": "rating"
    },
    "reviews.1.author": {
      "message": "Path `author` is required.",
      "name": "ValidatorError",
      "properties": {
        "type": "required",
        "message": "Path `{PATH}` is required.",
        "path": "author"
      },
      "kind": "required",
      "path": "author"
    }
  }
}

Here is my DB Schema for Locations:

var mongoose = require('mongoose');

var reviewSchema = new mongoose.Schema({
    author: {type: String, required: true},
    rating: {type: Number, required: true, min: 0, max: 5},
    reviewText: {type: String, required: true},
    createdOn: {type: Date, "default": Date.now}
});

var openingTimeSchema = new mongoose.Schema({
    days: {type: String, required: true},
    opening: String,
    closing: String,
    closed: {type: Boolean, required: true}
});

var locationSchema = new mongoose.Schema({
    name: {type: String, required: true},
    address: String,
    rating: {type: Number, "default":0, min: 0,  max: 5},
    facilities: [String],
    coords: {type: [Number], index:'2ndsphere'},
    openingTimes: [openingTimeSchema],
    reviews: [reviewSchema]
});

mongoose.model('Location', locationSchema);

Here the controller launched under router.post('/locations/:locationid/reviews', ctrlReviews.reviewsCreate); routing:

//reviews.js
var mongoose = require('mongoose');
var Loc = mongoose.model('Location');

module.exports.reviewsCreate = function (req, res) {
    var locationid = req.params.locationid;
    if(locationid){
        Loc
            .findById(locationid)
            .select('reviews')
            .exec(
                function(err, location){
                    if(err){
                        sendJsonResponse(res, 400, err);
                    } else{
                        console.log(location);
                        doAddReview(req, res, location);
                    }
                }
            );
    } else{
        sendJsonResponse(res, 400, {
            "message" : "Not found, locationid required"
        });
    }
};
// START - Functions for review create  //////////////////////////////////////
var doAddReview = function(req, res, location){
    if(!location){
        sendJsonResponse(res, 404, "locationid not found");
    } else{
        location.reviews.push({
            author: req.body.author,
            rating: req.body.rating,
            reviewText: req.body.reviewText
        });

        location.save(function(err, location){
            var thisReview;
            if(err){
                //sendJsonResponse(res, 400, err);
                sendJsonResponse(res, 400, err);
            } else{
                updateAverageRating(location._id);
                thisReview = location.reviews[location.reviews.length - 1];
                sendJsonResponse(res, 201, thisReview);
            }
        }); 
    }
};

var updateAverageRating = function(locationid){
    console.log("Update rating average for", locationid);
    Loc
        .findById(locationid)
        .select('reviews')
        .exec(
            function(err, location){
                if(!err){
                    doSetAverageRating(location);
                }
            }
        );
};

var doSetAverageRating = function(location){
    var i, reviewCount, ratingAverage, ratingTotal;
    if(location.reviews && location.reviews.length > 0){
        reviewCount = location.reviews.length;
        ratingTotal = 0;
        for(i=0; i<reviewCount; i++){
            ratingTotal = ratingTotal + location.reviews[i].rating;
        }
        ratingAverage = parseInt(ratingTotal / reviewCount, 10);
        location.rating = ratingAverage;
        location.save(function(err){
            if(err){
                console.log(err);
            } else{
                console.log("Average rating updated to", ratingAverage);
            }
        });
    }
};

I've seen that error pops when the location.save function is executed. I'm learning MEAN Stack from a book, so you'll be able to download the complete code for this chapter here: https://github.com/simonholmes/getting-MEAN/tree/chapter-06

I've tried replacing the code of my locations.js and reviews.js files from app_api/controllers folder, but at this point the application crashes, I guess because other files needs to be updated so. So I'm stuck there.

Does anyone understand why it would be happening?

Thanks in advance!

AtomicNation
  • 181
  • 1
  • 2
  • 6

6 Answers6

9

He bro.. Check this image.. I was also facing same problem.. and here is what I was doing wrong.enter image description here

Muhammad Ali
  • 341
  • 2
  • 7
5

I believe your problem might be that body-parser is not configured.

Try npm installing body-parser, then import it at the top of your main server file:

bodyParser = require('body-parser');

Finally, configure it for use. This will allow you to use x-www-form-urlencoded:

// Setting up basic middleware for all Express requests
app.use(bodyParser.urlencoded({ extended: false })); // Parses urlencoded bodies
app.use(bodyParser.json()); // Send JSON responses
Josh Slate
  • 774
  • 5
  • 17
  • Had a similar problem a bit ago happen to me and something along this was what solved it. – David Meents Jun 28 '16 at 16:06
  • Joshua I have it configured this way already, but I do not discard that the issue comes from some parse error, as each time I install a module I'm facing several warnings like this: "npm WARN EJSONPARSE Failed to parse json", maybe this is something related, but I couldn't find any solution for this (cache clear doesn't solve). – AtomicNation Jun 29 '16 at 10:16
2
Check your 

    req.body.author,
    req.body.rating,
    req.body.reviewText


They must be coming as empty string 
Piyush.kapoor
  • 6,715
  • 1
  • 21
  • 21
0

In fact. If, I change it for: author: "Big Mama", rating: 5, reviewText: "Lorem ipsum dolor amet" it works perfectly, but when I use Postman to add this in body it seems to be empty, and I think it should work. I'm using x-www-form-urlencode for this, but tried all other options. I'd like to undestand how should I use it here...

AtomicNation
  • 181
  • 1
  • 2
  • 6
0

Seems that this is sorted: I added id creation function in the review.push and working. Really I still don't understad why this is necessary, as usually mongoose add id's to documents and subdocuments, even I'm having problems with other controller because it's adding id's where shouldn't...Here the updated code for doAddReview function that sorted this issue:

var doAddReview = function(req, res, location){
    if(!location){
        sendJsonResponse(res, 404, "locationid not found");
    } else{
        location.reviews.push({
            _id: mongoose.Types.ObjectId(),
            author: req.body.author,
            rating: req.body.rating,
            reviewText: req.body.reviewText
            /*
            author: "Big Mama",
            rating: 5,
            reviewText: "Lorem ipsum dolor amet"
            */
        });

        location.save(function(err, location){
            var thisReview;
            if(err){
                //sendJsonResponse("Error Here");
                sendJsonResponse(res, 400, err);
            } else{
                updateAverageRating(location._id);
                thisReview = location.reviews[location.reviews.length - 1];
                sendJsonResponse(res, 201, thisReview);
            }
        }); 
    }
};

Many thanks Joshua and Piyush!

AtomicNation
  • 181
  • 1
  • 2
  • 6
0

Just make an curl call-

1.First import the curl command as Raw-text

enter image description here

2.Then send the POST request

Neeleshwar Kumar
  • 335
  • 3
  • 13