I am building a very simple RESTFUL app to see how Node and Mongo work together.
A made a function to find a "Persona" document on a mongodb by Id, so here is the code:
function getPersonabyId(req,res)
{
//en params del objeto request esta lo que llega por get
let idPersona=req.params.id;
//mongoose trae un método para pillar por id
Persona.findById(idPersona).exec((err,objPersona)=>
{
if(err)
{
res.status(500).send(err);
}
else{
res.status(200).send(objPersona);
}
})
}
And I use this route, where function is executed:
miniApp.get("/getPersonaById/:id",controladorPersona.getPersonabyId);
So, when I pass as parameter a valid ID, everything is ok, I get the proper Persona object in the response.
But when I use a not valid ID (no document with that ID exists on the mongodb), the error specified on the exec callback is thrown... but, isn´t supossed that this error should be thrown only in case there are server problems? a non existent ID should not be a 500 error, isn´t it?
I looked for info and I found this:
https://coursework.vschool.io/mongoose-crud/
Person.find((err, people) => {
// Note that this error doesn't mean nothing was found,
// it means the database had an error while searching, hence the 500 status
if (err) return res.status(500).send(err)
// send the list of all people
return res.status(200).send(people);
});
And reading the commented lines on the code above, confuses me even more... the error, as said in those comments, should be an error database or something similar, not a "not found" error... but the error is actually thrown when an object with that ID is not found!
This is the error I get with a non valid ID:
{
"message": "Cast to ObjectId failed for value \"5b105ba453401c41d0e3da2\" at path \"_id\" for model \"Persona\"",
"name": "CastError",
"stringValue": "\"5b105ba453401c41d0e3da2\"",
"kind": "ObjectId",
"value": "5b105ba453401c41d0e3da2",
"path": "_id"
}
As you are using mongoose, you can validate that the incoming value is an objectId or not by using mongoose.Types.ObjectId.isValid(req.params.id). This will return a boolean and possibly save you some effort or writing the regex for object Id validation.
You have defined your _id as ObjectId in schema. Not every string is a valid ObjectId. the id tha you are passing to findById is not valid. Object id should be 24 characters long string. Add this check before querying,
if (id.match(/^[0-9a-fA-F]{24}$/)) {
// Yes, it's a valid ObjectId, proceed with `findById` call.
} else{
//throw an error
}
or if you want to keep using any string as _id, define _id as String instead of ObjectId in your schema.
I am running into following error but I unable to completely grasp the understanding behind the error.
CastError: Cast to ObjectId failed for value "XYZ" at path "_id" for model "Partner"
I have my schema defined as following
var partnerList = new Schema (
{
partnerName: String,
supportedProducts: [String]
},
{
collection: 'partnerList'
}
);
module.exports = mongoose.model('Partner', partnerList);
The functionality of my delete function
delete: function (req, res) {
var removePartner = req.params.partnerName;
var promise = Partner.findByIdAndRemove(removePartner).exec();
promise.then(function removePartner(val) {
console.log('partner value removed');
res.send(val);
}).catch(function catchError(err){
console.error(err);
throw err;
});
}
I am trying to making a request to my node app service using
localhost:8443/data/XYZ, where i am passing the value 'XYZ' as the parameter. This value is used to delete the appropriate object from the database.
Basically the error means that whatever you pass as your "XYZ" url param is not a valid ObjectId.
Guessing from your code you use the "partner name" (probably some arbitrary string) instead of the database id of the partner. However findByIdAndRemove() requires you to specify an ObjectId as it uses this to identify which document to delete:
Model.findByIdAndRemove(id, [options], [callback])
Your delete API call could then look something like this: http://localhost:8443/data/59558ccd7acc4dd63ea88988. However for this the client needs to know the ObjectId of the partner.
So you have to either use the ObjectId of a partner in the URL, or use remove() to implement your custom delete query instead, for example like this (if name is the property you use to store your partner names):
Partner.remove({ name: partnerName }).exec();
Be careful however that this might remove multiple documents if your partner name is not unique, as remove will delete all documents matching the query.
In order to prevent this you can also use findOneAndRemove() using the same query. This would only remove one document at a time. If there are multiple partners with the same name it would remove the first one (depending on your sort order).
I am getting ObjectId from one table and want to save another table which has column field name 'owner' with datatype 'Pointer<_User>'. But when I tried to do this I got this error 'invalid type for key owner, expected *_User, but got string'.
Please help me out. Thanks.
The problem lies in the title of the question. The operand to a pointer column isn't an object id, it is an object.
So if you have an object, say a PFUser, do this:
// user is a PFUser
myObjectThatPointsToUser("owner", user);
If you have only a user's object id as a string, ask yourself why. To the extent you can, design to converse in objects, not ids. But if you find yourself in this situation, set the pointer column like this:
// userId is the id of a PFUser
var userStub = { "__type": "Pointer",
"className": "_User",
"objectId": userId };
myObjectThatPointsToUser("owner", userStub);
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.
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.
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
})
For all those people stuck with this problem, but still couldn't solve it: I stumbled upon the same error and found the _id field being empty.
I described it here in more detail. Still have not found a solution except changing the fields in _id to not-ID fields which is a dirty hack to me. I'm probably going to file a bug report for mongoose. Any help would be appreciated!
Edit: I updated my thread. I filed a ticket and they confirmed the missing _id problem. It is going to be fixed in the 4.x.x version which has a release candidate available right now. The rc is not recommended for productive use!
If you are having this issue and you are performing a populate somewhere along the lines, see this Mongoose issue.
Update to Mongoose 4.0 and the issue has been fixed.
Had the same problem, I just coerced the id into a string.
My schema:
const product = new mongooseClient.Schema({
retailerID: { type: mongoose.SchemaTypes.ObjectId, required: true, index: true }
});
And then, when inserting:
retailerID: `${retailer._id}`
I had the same problem, turned out after I have updated my schema, I have forgotten I was calling the model using the old id, which was created by me; I have updated my schema from something like:
patientid: {
type: String,
required: true,
unique: true
},
to
patientid: { type: mongoose.SchemaTypes.ObjectId, ref: "Patient" },
It turned out, since my code is big, I was calling the findOne with the old id, therefore, the problem.
I am posting here just to help somebody else: please, check your code for unknown wrong calls! it may be the problem, and it can save your huge headacles!
My solution is that I want data from all docs, and I don't want _id, so
User.find({}, {_id:0, keyToShow:1, keyToNotShow:0})
I was receiving this error CastError: Cast to ObjectId failed for value “[object Object]” at path “_id” after creating a schema, then modifying it and couldn't track it down. I deleted all the documents in the collection and I could add 1 object but not a second. I ended up deleting the collection in Mongo and that worked as Mongoose recreated the collection.
For the record: I had this error trying to fill a subdocument in a wrong way:
{
[CastError: Cast to ObjectId failed for value "[object Object]" at path "_id"]
message: 'Cast to ObjectId failed for value "[object Object]" at path "_id"',
name: 'CastError',
type: 'ObjectId',
path: '_id'
value:
[ { timestamp: '2014-07-03T00:23:45-04:00',
date_start: '2014-07-03T00:23:45-04:00',
date_end: '2014-07-03T00:23:45-04:00',
operation: 'Deactivation' } ],
}
look ^ value is an array containing an object: wrong!
Explanation: I was sending data from php to a node.js API in this way:
$history = json_encode(
array(
array(
'timestamp' => date('c', time()),
'date_start' => date('c', time()),
'date_end' => date('c', time()),
'operation' => 'Deactivation'
)));
As you can see $history is an array containing an array. That's why mongoose try to fill _id (or any other field) with an array instead than a Scheme.ObjectId (or any other data type). The following works:
$history = json_encode(
array(
'timestamp' => date('c', time()),
'date_start' => date('c', time()),
'date_end' => date('c', time()),
'operation' => 'Deactivation'
));
I am not sure this will help but I resolved the issue by importing mongoose like below and implementing it as below
const mongoose = require('mongoose')
_id: new mongoose.Types.ObjectId(),
I also encountered this mongoose error
CastError: Cast to ObjectId failed for value \"583fe2c488cf652d4c6b45d1\" at path \"_id\" for model User
So I run npm list command to verify the mongodb and mongoose version in my local.
Heres the report:
......
......
├── mongodb#2.2.19
├── mongoose#4.7.2
.....
It seems there's an issue on this mongodb version so what I did is I uninstall and try to use different version such as 2.2.16
$ npm uninstall mongodb, it will delete the mongodb from your node_modules directory. After that install the lower version of mongodb.
$ npm install mongodb#2.2.16
Finally, I restart the app and the CastError is gone!!
I was having the same problem.Turns out my Node.js was outdated. After upgrading it's working.
just change the path it will work for example
app.get('/myClass/:Id/childClass/create', function(request, result) .....
change to
app.get('/myClass**es**/:Id/childClass/create', function(request, result) .....
I just added --es-- to the path (myClass) to become (myClasses)
now should work and will not see that error
For me, the ID was undefined (req.params.id returns undefined)
If you're finding a document by its "_id" for a model, say Drivers, the command below works quite well:
....
const driver = await Drivers.findById(<your id>);
....
Ensure you use the async-await and try-catch ES6 syntax
For me, I was using a put request without sending any data. I changed it to a post request and it worked.
This thread covers more about put requests.
just change the path it will work for example
app.get('/myClass/:Id/childClass/create', function(request, result)
change to
app.get('/myClass**es**/:Id/childClass/create', function(request, result)
I just added --es-- to the path (myClass) to become (myClasses)
now should work and will not see that error