Nate
Nate

Reputation: 65

CastError: Cast to ObjectId failed for value "customers" at path "_id" for model "customer"

I was hoping someone can help me figure out what I'm doing wrong here. I've been searching and I can find a lot of similar issues, but nothing that I'm smart enough to solve my issue from. I'm getting the following error:

CastError: Cast to ObjectId failed for value "customers" at path "_id" for model "customer"

It was working before and I managed to break it, and I undid everything I thought I changed and I'm still getting the error.

Here is my Schema:

const Schema = mongoose.Schema;

const CustomerSchema = new Schema({

  custName: {
    type: String,
    required: true
  },
  custStreet: {
    type: String
  },
  custCity: {
    type: String
  },
  custState: {
    type: String
  },
  custZip: {
    type: String
  }
});

module.exports = Customer = mongoose.model('customer', CustomerSchema); 

My Routes:

const router = express.Router();

const customerController = require('../../controllers/customer')

const Customer = require('../../models/Customer');

router.route('/')
  .get(customerController.index)
  .post(customerController.newCustomer);

router.route('/:customerID')
  .get(customerController.getCustomer)

module.exports = router;

And my controller:


module.exports = {

  index: async (req, res, next) => {
    try {
    const customers = await Customer.find({})
    res.status(200).json(customers);
  } catch(err) {
      next(err);
    }
  },

  newCustomer: async (req, res, next) => {
    try {
    const newCustomer = await Customer(req.body);
    const customer = await newCustomer.save();
    res.status(201).json(customer);
      } catch(err) {
          next(err);
      }
  }, 

  getCustomer: async(req, res, next) => {
    try {
    const { customerID } = req.params;
    const customer= await Customer.findById(customerID);
    res.status(200).json(customer);  
    } catch(err) {
        next(err);
    }
  }
};

Also, here is the whole message I get:

CastError: Cast to ObjectId failed for value "customers" at path "_id" for model "customer" at model.Query.exec (C:\Users\natha\Desktop\Coding\HAMMER\node_modules\mongoose\lib\query.js:4371:21) at model.Query.Query.then (C:\Users\natha\Desktop\Coding\HAMMER\node_modules\mongoose\lib\query.js:4463:15) at processTicksAndRejections (internal/process/task_queues.js:93:5)

Something else that is confusing me, I have another Route file and Controller for another collection in my database. It's basically the same code, except instead of routing to '/:Customers' it routes to '/:Tickets' and it works just fine. I don't see how this code is working and the Customers code is not.

Routes:

const router = express.Router();

const ticketController = require('../../controllers/ticket');

router.route('/')
  .get(ticketController.index)
  .post(ticketController.newTicket);

router.route('/:ticketID')
  .get(ticketController.getTicket)
  .put(ticketController.replaceTicket)
  .patch(ticketController.updateTicket);

module.exports = router;

Controller:


module.exports = {

 index: async(req, res, next) => {
   try {
     const tickets = await Ticket.find({})
     res.status(200).json(tickets);
   } catch(err) {
     next(err);
   }
 },

 newTicket: async (req, res, next) => {
   try {
     const newTicket = await Ticket(req.body);
     const ticket = await newTicket.save();
     res.status(201).json(ticket);
   } catch(err) {
      next(err);
   }
 },

 getTicket: async(req, res, next) => {
  try {
  const { ticketID } = req.params;
  const ticket = await Ticket.findById(ticketID);
  res.status(200).json(ticket);
  } catch(err) {
      next(err);
  }
 }, 

 replaceTicket: async(req, res, next) =>{
   try {
     const { ticketID } = req.params;
     const newTicket = req.body;
     const result = await Ticket.findByIdAndUpdate(ticketID, newTicket);
     res.status(200).json({ Success: true });
   } catch(err) {
      next(err);
   }
 },

 updateTicket: async(req, res, next) =>{
   try {
     const { ticketID } = req.params;
     const newTicket = req.body;
     const result = await Ticket.findByIdAndUpdate(ticketID, newTicket);
     res.status(200).json({ Success: true });
   } catch(err) {
      next(err);
   }
 } 
};

I'd appreciate any help!

Thanks

-N8

Upvotes: 1

Views: 2864

Answers (3)

Tosin Coker
Tosin Coker

Reputation: 92

I upvoted the solution of the OP. To save a lot of time, I just want to explain why that is an issue and what someone else could look out for as I. So in OP server.js, '/' comes before other routes which defy the rule to list specific routes first. Meaning, if '/' was moved after other routes problem is solved. More importantly, where does this error come from? when you call any of the other routes, your app calls '/' first and uses the customers' routes while passing the route paths (i.e. '/customers', '/materials', '/tickets') as id params and then mongo is trying to cast customer, materials, and tickets as an id inside the customer collection.

app.use('/customers', customers);
app.use('/materials', materials)
app.use('/tickets', tickets)
app.use('/', customers);

This will have solved the problem for OP.

In my case this was the problem:

router.get('/', getAllUser);
router.get('/:id', getUserById)
router.get('/facebook', facebookPassport)
router.get('/google', customersPassport);

So here I get this error Cast error for value "facebook"/"google" at path "_id" for model User because the strings, "facebook" and "google" in the last two routes are specific but will never be reached because the '/:id' route will accept any value that comes after the '/' as an id. When I rearrange like this:

router.get('/', getAllUser);
router.get('/facebook', facebookPassport)
router.get('/google', customersPassport);
router.get('/:id', getUserById)

Take away: move specific routes to the top of dynamic routes (routes with params) both at the app level and in your route files.

Upvotes: 2

Nate
Nate

Reputation: 65

I found the problem. I had this in my server.js file:

app.use('/', customers);
app.use('/customers', customers);
app.use('/materials', materials)
app.use('/tickets', tickets)

Once I got rid of the app.use('/', customers); all is good.

Upvotes: 2

Abbas
Abbas

Reputation: 1255

You have an error in getCustomer handler.

You shouldn't use the string id to find the customer, instead, you must first use mongoose.Types.ObjectId(STRING_ID).

getCustomer: async(req, res, next) => {
    try {
    const { customerID } = req.params;
    const customer= await Customer.findById(mongoose.Types.ObjectId(customerID));
    res.status(200).json(customer);  
    } catch(err) {
        next(err);
    }
  }

Upvotes: 0

Related Questions