Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose: CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"

I am new to node.js, so I have a feeling that this will be something silly that I have overlooked, but I haven't been able to find an answer that fixes my problem. What I'm trying to do is create a path that will create a new child object, add it to the parent's array of children, then return the child object to the requester. The problem that I am running into is that if I pass the string id into findById, node crashes with

TypeError: Object {} has no method 'cast'

If I try to pass in an ObjectId instead, I get

CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"

Here is a rough outline of my code:

var mongoose = require('mongoose'); var Schema = mongoose.Schema; var ObjectId = Schema.ObjectId; //Have also tried Schema.Types.ObjectId, mongoose.ObjectId  mongoose.connect('mongodb://user:password@server:port/database');  app.get('/myClass/:Id/childClass/create', function(request, result) {   var id = new ObjectId(request.params.Id);   MyClass.findById(id).exec( function(err, myClass) {     if (err || !myClass) { result.send("error: " + err + "<br>" + JSON.stringify(id) || ("object '" + request.params.Id + "' not found: " + id)); return; }     var child = ChildClass();     myClass.Children.addToSet(child);     myClass.save();     result.send(child);   }); }); 

If I execute this code with the path "/myClass/51c35e5ced18cb901d000001/childClass/create", this is the output of the code:

error: CastError: Cast to ObjectId failed for value "[object Object]" at path "_id" {"path":"51c35e5ced18cb901d000001","instance":"ObjectID","validators":[],"setters":[],"getters":[],"_index":null}

I've tried using findOne and passing in {_id:id} instead, but this appears to be exactly what findById does. I've tried the different classes for ObjectId that I've seen listed on other sites. I've tried calling ObjectId() like a function instead of a constructor and that returns undefined. At this point, I'm running out of ideas and it doesn't seem that googling for an answer is helping. Any ideas on what I'm doing wrong?

Also, like I said, I'm new to node/Mongo/Mongoose/Express, so if there is a better way to accomplish my goal, please let me know. I appreciate all feedback.

EDIT:

After the workaround from Peter Lyons, I googled another error that I was running into and found findByIdAndUpdate, which works as expected and does exactly what I was hoping to do. I'm still not sure why findById and findOne were giving me such issues and I'm curious to know (maybe a bug report needs to be filed), so I'll leave this open in case someone else has an answer.

like image 439
jmblackmer Avatar asked Jun 20 '13 20:06

jmblackmer


People also ask

What is Mongoose cast error?

it happens when you pass an invalid id to mongoose. so first check it before proceeding, using mongoose isValid function import mongoose from "mongoose"; // add this inside your route if( !

What is ObjectId in mongoose?

ObjectId . A SchemaType is just a configuration object for Mongoose. An instance of the mongoose. ObjectId SchemaType doesn't actually create MongoDB ObjectIds, it is just a configuration for a path in a schema.

What is a cast error?

25 July 2015 Error of Casting Definition: An error due to which total of an account is more or less recorded is known as error of casting.


2 Answers

Short answer: use mongoose.Types.ObjectId.

Mongoose (but not mongo) can accept object Ids as strings and "cast" them properly for you, so just use:

MyClass.findById(req.params.id) 

However, the caveat is if req.params.id is not a valid format for a mongo ID string, that will throw an exception which you must catch.

So the main confusing thing to understand is that mongoose.SchemaTypes has stuff you only use when defining mongoose schemas, and mongoose.Types has the stuff you use when creating data objects you want to store in the database or query objects. So mongoose.Types.ObjectId("51bb793aca2ab77a3200000d") works, will give you an object you can store in the database or use in queries, and will throw an exception if given an invalid ID string.

findOne takes a query object and passes a single model instance to the callback. And findById is literally a wrapper of findOne({_id: id}) (see source code here). Just find takes a query object and passes an array of matching model instances to the callback.

Just go slow. It's confusing but I can guarantee you you are getting confused and not hitting bugs in mongoose at this point. It's a pretty mature library, but it takes some time to get the hang of it.

The other suspect thing I see in your snippet is not using new when instantiating ChildClass. Beyond that, you'll need to post your schema code in order for us to help you tract down any CastErrors that remain.

like image 192
Peter Lyons Avatar answered Sep 24 '22 16:09

Peter Lyons


I've faced this error, That was because the value you want to filter in the _id field is not in an ID format, one "if" should solve your error.

const mongoose = require('mongoose');  console.log(mongoose.Types.ObjectId.isValid('53cb6b9b4f4ddef1ad47f943')); // true console.log(mongoose.Types.ObjectId.isValid('whatever')); // false 

To solve it, always validate if the criteria value for search is a valid ObjectId

const criteria = {}; criteria.$or = [];  if(params.q) {   if(mongoose.Types.ObjectId.isValid(params.id)) {     criteria.$or.push({ _id: params.q })   }   criteria.$or.push({ name: { $regex: params.q, $options: 'i' }})   criteria.$or.push({ email: { $regex: params.q, $options: 'i' }})   criteria.$or.push({ password: { $regex: params.q, $options: 'i' }}) }  return UserModule.find(criteria).exec(() => {   // do stuff }) 
like image 20
gsalgadotoledo Avatar answered Sep 26 '22 16:09

gsalgadotoledo