Cast to ObjectId failed for value (reference to files) - node.js

As the title says.
For more context : I have a small script (launched by php via exec) that will search for a chapter with a given id to do some changes on the images (scramble them) that I didn't manage to do in php (I'm newbie working with files).
here are my schema
//instantiate mongoose-gridfs
var gridfs = require('mongoose-gridfs')({
collection:'files',
mongooseConnection: mongoose.connection
});
//Files = gridfs.model;
var FilesSchema = gridfs.schema;
FilesSchema.add({
_id: Schema.Types.ObjectId,
name: String,
mime: String,
filename: String,
type: String
});
Files = mongoose.model('Files', FilesSchema);
var pageSchema = Schema({
order: Number,
image: { type: Schema.Types.ObjectId, ref: 'Files' },
scrambled: Boolean
});
var ChapterSchema = Schema({
_id: Schema.Types.ObjectId,
pages: [pageSchema]
});
var Chapter = mongoose.model('Chapter', ChapterSchema, "Chapter");
When I do that
Chapter.findById(chapterId)
.populate('pages.image')
exec(...
It raises the CastError : { CastError: Cast to ObjectId failed for value "DBRef ...
The error object is long, so I don't paste it here
but here is a pastebin with the full error message/object
https://pastebin.com/8n54Dhzt
If I chan,ge the type of Image to Array I can access the properties I need after, but in that case I can't reset the images properly (it writes an array on db instead of a Ref)
My ref is in an embeddedDocument, like that
Chapter.pages[0].image
image is the property that have the ref.
I don't really understand why I have this error, I followed the docs for the refs/populate : http://mongoosejs.com/docs/populate.html
PS : A detail that can be important, The Reference is saved by DoctrineODM.
I use my node script to modify/encrypt the image, and then revert the encryption in js on my app.
PS2: sorry if a similar question is already posted and answered, there is so much post with the same error 'Cast to ObjectId failed for value' I admit I didn't read all of them, but those I read didn't help me.
EDIT : Update my code to use mongoose-gridfs Model instead of a different one + use subDocument instead of Array of object

Well that seems an error with chapterIdvalue. When you use collection.findById, the passed value must pass the ObjectId criteria which is
12-byte structure, the first 4 bytes of the ObjectId represent the
time in seconds since the UNIX epoch.
The next 3 bytes of the ObjectId represent the machine identifier.
The next 2 bytes of the ObjectId represent the process ID.
And the last 3 bytes of the ObjectId represent a random counter
value.
And if your passed id is not constructable to the pattern mentioned above this is definitely gonna throw the errors like you're getting.
So make sure you chapterId is correct or it is the same what you are getting from the database

Related

How to check for empty object id in populate method?

I'm trying to populate array of objects using the following code:
inventory.populate(result, {
path: 'activities.mean',
$match: { 'activities.mean': {$ne: ''} }
}, callback);
where type of mean is:
mean:{type:String, ref: 'Inventory'}
While populating a result I get the error in my callback function:
CastError: Cast to ObjectId failed for value "" at path "_id" for model "Inventory"'...
Which clearly shows that I've results that contains empty activities.mean.
I tried different solutions provided including match that I wrote in above code but I can't really make it work. Not sure why match is not working here.
What I'm expecting this code to do is:
if activities.mean is empty string, then do not try to populate that mean.
More looks like that the issue is that you're using String type for a reference field – because of that mongoose is trying to cast string values to ObjectId which is normally used for references. It should be
mean: {
type: Schema.Types.ObjectId,
ref: 'Inventory'
}
Mongoose's documentation itself notes that
Note: ObjectId, Number, String, and Buffer are valid for use as refs. However, you should use ObjectId unless you are an advanced user and have a good reason for doing so.

Mongoose: Cast to array of object failed for value [{"someKey": "someValue"}]

I'm getting error whenever I'm trying to save into my database a document with this schema:
var schemaForBooks = new Schema({
book: String,
author: String,
who_has_this: Object,
points: Number,
upvoted_by_users: [Schema.Types.ObjectId],
downvoted_by_users: [Schema.Types.ObjectId]
});
Rest all is good, but putting anything into upvoted_by_users or downvoted_by_users, I get this error:
[ERROR] Trace- CastError: Cast to [ObjectId] failed for value "[{"userName":"Vibhu","userId":"3833d1g870feaf4a38723"}]" at path "upvoted_
by_users"
I'm pretty sure I'm doing something wrong with the schema itself, but I don't know what.
Any help would be appreciated.
The error says that you're trying to cast the following array of object {"userName":"Vibhu", "userId":"3833d1g870feaf4a38723"} to an array of ObjectId.
So, you need to get rid of the userName field, so you can turn your array of String + ObjectId to an array of ObjectId.
You can do it with the Array#map method on your js Array, for example :
var arr = [{"userName":"Vibhu","userId":"3833d1g870feaf4a38723"}];
var myCorrectArr = arr.map(field => field.userId);
Hope it helps,
Best regards,

node.js: limit number of object Ids that an array contain in mongodb using mongoose

May be my question is so simple but I'm not finding a solution for it.
I want to limit the size of array of object Ids in mongodb. I'm using mongoose.
how to do this using mongoose schema?
or The solution I'm thinking is first retrieve the document then calculate the size of array and after that return the validation failure error to the end user if it occurs.
Please help me find the better solution.
There's no such thing in Mongoose, but you can define your own validation. According to Mongoose documentation, you can do that:
var userSchema = new Schema({
phone: [{
type: ObjectId,
validate: {
validator: function() {
return this.phone.length <= 100;
},
message: 'Array exceeds max size.'
}
}]
});
For an array the validator function is called for each element with the element as parameter. But you can check the property's length instead of validating an element.
That will work when you update your model instance with the save method. Validators are not run when using User.update.

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.
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

Programming with node.js and mongoose. Error id want to pass the value to update registration

I'm learning to use with mongoose and node.js when editing to generate a content that gives me the error: 500 TypeError: Can not read property 'ObjectID' of undefined. Check whether the parameter that I send comes empty and is not.
Remove the option and gives me that error when saving the data did not find the method I use to save some registry update.
If I can help as I have code in https://github.com/boneyking/PruebaNode.git
First of all, please provide code or at least a link to the code. A link to your github repo is not cool !!!
Now back to the question... Add an id to your model and get it like other types:
var SUPER = mongoose.model('Producto',{
nombre: String,
descripcion: String,
precio: Number,
id: mongoose.Schema.Types.ObjectId
});
SUPER.editar = function(newData, callback){
SUPER.findOne({id: newData.id}, function(e,o){
o.nombre = newData.nombre;
o.descripcion = newData.descripcion;
o.precio = newData.precio;
SUPER.save(o);
callback(o);
});
}

Resources