Reputation: 31
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
Reputation: 7
I have the same problem. You need to put route with aggregation before route with "../:id"
Upvotes: -1
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
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.
Upvotes: 7