I am currently creating simple CRUD app that lets me create products and store it in a Mongo database. The app is working fine, except that it is constantly throwing an error message when I try to go to my ‘/products/show’ page (or when working with a specific product).
I don’t really know what is happening as this is my first time working with Mongoose and MongoDB. The app is working fine, which it should, but this error message is causing the program to continue loading even when everything is on the screen.
My index.js file
const express = require('express');
const app = express();
const path = require('path');
const mongoose = require('mongoose');
const Product = require('./models/product');
mongoose.connect('mongodb://localhost:27017/farmStand', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log("MONGO CONNECTION IS OPEN!");
})
.catch(err => {
console.log("Oh no.. Mongo error");
console.log(err);
});
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true }));
app.get('/products', async (req, res) => {
const products = await Product.find({});
res.render('products/index', { products });
});
app.get('/products/new', (req, res) => {
res.render('products/new');
});
app.post('/products', async (req, res) => {
const newProduct = new Product(req.body);
await newProduct.save();
console.log(newProduct);
res.redirect(`/products/${newProduct._id}`);
});
// This is where the error is occuring.
app.get('/products/:id', async (req, res) => {
try {
const product = await Product.findById(req.params.id);
res.render('products/show', { product });
}
catch (error) {
console.log(error);
}
});
app.listen(3000, () => {
console.log("APP IS LISTENING ON PORT 3000");
});
My productSchema file
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
price: {
type: Number,
required: true,
min: 0
},
category: {
type: String,
lowercase: true,
enum: ['fruit', 'vegetables', "dairy"]
}
});
const Product = mongoose.model('Product', productSchema);
module.exports = Product;
My EJS ‘/show’ file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= product.name %></title>
</head>
<body>
<h1><%= product.name %></h1>
<ul>
<li>Price: $<%= product.price %></li>
<li>Category: <%= product.category %></li>
</ul>
<a href="/products">All products</a>
</body>
</html>
The error message
CastError: Cast to ObjectId failed for value "null" (type string) at path "_id" for model "Product"
at ObjectId.cast (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/schema/objectid.js:250:11)
at SchemaType.applySetters (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/schematype.js:1220:12)
at SchemaType.castForQuery (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/schematype.js:1632:15)
at cast (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/cast.js:356:32)
at Query.cast (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:4910:12)
at Query._castConditions (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:2232:10)
at model.Query._findOne (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:2519:8)
at model.Query.exec (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:4429:28)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async /Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/index.js:40:25 {
stringValue: '"null"',
messageFormat: undefined,
kind: 'ObjectId',
value: 'null',
path: '_id',
reason: BSONError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer
at new ObjectId (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/bson/lib/bson.cjs:2006:23)
at castObjectId (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/cast/objectid.js:25:12)
at ObjectId.cast (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/schema/objectid.js:248:12)
at SchemaType.applySetters (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/schematype.js:1220:12)
at SchemaType.castForQuery (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/schematype.js:1632:15)
at cast (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/cast.js:356:32)
at Query.cast (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:4910:12)
at Query._castConditions (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:2232:10)
at model.Query._findOne (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:2519:8)
at model.Query.exec (/Users/nielskoop/Coding/UdemyCourse/MongoDB/38_mongoose-express/node_modules/mongoose/lib/query.js:4429:28),
valueType: 'string',
model: Model { Product }
}
Solutions I have tried
I could not really find much information on this subject online, and the information that was available was quite confusing. I’ve tried adding an if
statement to check whether the given id isValid
, but that just stops the program from working altogether. I also tried to convert the ID given by Mongoose into a simple string and store it in a separate variable so that I could work with it later, but that also stopped the program from working altogether.
Desired solution
I would like to find out what is causing this error and how to fix it. I have the feeling that when I go to the ‘/show’ page the code continues running and checking for a new ID value in Mongoose, which is not there. I might be completely wrong, however.
Thanks in advance!
2
Answers
Okay, it turns out that I was very close with my solution by putting the
findByID()
call in anif
statement. This is my code now:It does not throw the error message anymore. My question now is if this code is good like this, or if it can be improved in some way? Also, the page continues loading until eternity, and that is a thorn in my eye. Is that normal behavior, or is that not good? If it's not good, how do I fix it? 😊
You absolutely don’t need to run an
if (id.match...){...}
statement to make yourfindById(id)
work.The error message tells you that:
So in this code:
I suspect than on some occasions something is not quite right with your
const newProduct
and mongoose is not creating the Product, which then has a knock on effect when you try to redirect. You think you are redirecting to:but in actual fact you are redirecting to:
So
req.params.id
isnull
in your:You need a
try/catch
block in yourapp.post('/products'...)
to find out when the creation of a product is failing. At the minute you just blindly redirect. Implement this change:Your code looks pretty good otherwise and it’s maybe just an issue with the data you are actually posting that is causing the Product not to create.