Mongoose: CastError: 转换为 ObjectId 失败,路径“_id”的值为“[ Object Object ]”

我是 node.js 的新手,所以我有一种感觉,这将是一些愚蠢的东西,我忽略了,但我还没有能够找到一个解决我的问题的答案。我试图做的是创建一个路径,该路径将创建一个新的子对象,将其添加到父对象的子对象数组中,然后将子对象返回给请求者。我遇到的问题是,如果我将字符串 id 传递给 findById,节点会崩溃

TypeError: 对象{}没有“强制转换”方法

如果尝试传入 ObjectId,则会得到

CastError: 转换为 ObjectId 失败,路径“ _ id”的值为“[ Object Object ]”

下面是我的代码的大致轮廓:

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);
});
});

如果我使用“/myClass/51c35e5ced18cb901d000001/child Class/create”路径执行这段代码,这是代码的输出:

错误: CastError: 转换为 ObjectId 失败,路径“ _ id”的值为“[ Object Object ]” {“ path”: “51c35e5ced18cb901d00001”,“ instance”: “ ObjectID”,“ validators”: [] ,“ setters”: [] ,“ getters”: [] ,“ _ index”: null }

我尝试使用 findOne 并传入{ _ id: id } ,但这似乎正是 findById 所做的。我已经尝试了其他站点上列出的 ObjectId 的不同类。我曾尝试像函数一样调用 ObjectId () ,而不是像调用构造函数一样调用 ObjectId () ,结果返回未定义的。此时此刻,我已经想不出什么办法了,而且似乎在谷歌上搜索答案也没什么帮助。知道我哪里做错了吗?

另外,正如我所说的,我是节点/Mongo/猫鼬/Express 的新手,所以如果有更好的方法来实现我的目标,请让我知道。感谢你们的反馈。

编辑:

在从 Peter Lyons 那里得到解决方案之后,我在谷歌上搜索了我遇到的另一个错误,找到了 findByIdAndUpdate,它的工作方式和预期的一样,完全符合我的期望。我仍然不确定为什么 findById 和 findOne 会给我这样的问题,我很好奇(也许需要提交一个 bug 报告) ,所以我将把这个打开,以防其他人有答案。

228144 次浏览

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 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'
));

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.

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
})

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.

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}`

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

My solution is that i want data from all docs and i dont want _id, so

User.find({}, {_id:0, keyToShow:1, keyToNotShow:0})

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!

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(),

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