singu
singu

Reputation: 31

"Cast to ObjectId failed for value \"\" at path \"_id\" for model \"ModelName\""-Mongoose

I am trying to use aggregation based on my mongoose model. Please look into this and help me out with the error and give any suggestions.Error: "message": { "message": "Cast to ObjectId failed for value \"tour-stats\" at path \"_id\" for model \"Tour\"",

Route

router.get('/tour-stats', tour.getTourStats);

Controller

exports.getTourStats = async (req, res) => {
try {
const stats = await Tour.aggregate([
  {
    $match: { ratingsAverage: { $gte: 4.5 } }
  },
  {
    $group: {
      _id: null,
      numTours: { $sum: 1 },
      numRatings: { $sum: '$ratingsQuantity' },
      avgRating: { $avg: '$ratingsAverage' },
      avgPrice: { $avg: '$price' },
      minPrice: { $min: '$price' },
      maxPrice: { $max: '$price' }
    }
  },
  {
    $sort: { avgPrice: 1 }
  }
  // {
  //   $match: { _id: { $ne: 'EASY' } }
  // }
]);

res.status(200).json({
  status: 'success',
  data: {
    stats
  }
});
} catch (err) {
res.status(404).json({
  status: 'fail',
  message: err
});
}
};

Tour Model

const tourSchema = new mongoose.Schema(
{
name: {
  type: String,
  required: [true, 'A tour must have a name'],
  unique: true,
  trim: true,
},
duration: {
  type: Number,
  required: [true, 'A tour must have a duration'],
},
maxGroupSize: {
  type: Number,
  required: [true, 'A tour must  have a group size'],
},
difficulty: {
  type: String,
  required: [true, 'A tour must have a difficulty'],
},
ratingsAverage: {
  type: Number,
  default: 4.5,
},
ratingsQuantity: {
  type: Number,
  default: 0,
},
price: {
  type: Number,
  required: [true, 'A tour must have a price '],
},
priceDiscount: Number,
summary: {
  type: String,
  trim: true,
  required: [true, 'A tour must have a decription'],
},
description: {
  type: String,
  trim: true,
},
imageCover: {
  type: String,
  required: [true, 'A tour must have a cover image'],
},
images: [String],
createdAt: {
  type: Date,
  default: Date.now(),
},
 startDates: [Date],
 }
 // { timestamps: true }
);

Sample document:

{ "id": 8, "name": "The Northern Lights", "duration": 3, "maxGroupSize": 12, "difficulty": "easy", "ratingsAverage": 4.9, "ratingsQuantity": 33, "price": 1497, "summary": "Enjoy the Northern Lights in one of the best places in the world", "description": "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua, ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", "imageCover": "tour-9-cover.jpg", "images": ["tour-9-1.jpg", "tour-9-2.jpg", "tour-9-3.jpg"], "startDates": ["2021-12-16,10:00", "2022-01-16,10:00", "2022-12-12,10:00"] }

Thanks in Advance.

Upvotes: 0

Views: 1572

Answers (3)

Myroslav
Myroslav

Reputation: 7

I have the same problem. You need to put route with aggregation before route with "../:id"

Upvotes: -1

Bilal Mohmand
Bilal Mohmand

Reputation: 51

In your route file put the stats route above all below example in my case

//GET USER STATS

router.get("/stats", async (req, res) => {});

//UPDATE
router.put("/:id", async (req, res) => {});

//DELETE
router.delete("/:id", async (req, res) => {});

// GET USER
router.get("/:id",  async (req, res) => {});

//GET ALL USERS
router.get("/", async (req, res) => {});

Upvotes: 0

Greg
Greg

Reputation: 175

I've also taken this course and was struggling to understand what's going on, and finally found it. In my case, it happened because of the wrong order of the routes.

When you're trying to send request to "api/v1/tours/tour-stats" you actually sending request to "api/v1/tours/:id" and "tour-stats" goes as id to this route (obviously invalid), causing an error. So be sure that your "tour-stats" route defined before your id route.

enter image description here

Upvotes: 7

Related Questions