提问者:小点点

Mongoose:CastError:将路径“_id”处的值“[object object]”转换为ObjectId失败


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

TypeError:对象{}没有方法“cast”

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

CastError:将路径“_id”处的值“[object object]”强制转换为ObjectId失败

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

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/childclass/create”执行此代码,这是代码的输出:

错误:CastError:将路径“_id”{“path”:“51c35e5ced18cb901d000001”,“instance”:“ObjectId”,“validators”:[],“setters”:[],“getters”:[],“_index”:null}处的值“[object object]”强制转换为ObjectId失败

我尝试使用findOne并传入{_id:id},但这似乎正是findById所做的。我尝试了ObjectId的不同类,我在其他站点上看到了这些类。我尝试像函数一样调用ObjectId(),而不是构造函数,结果返回未定义。在这一点上,我的想法耗尽了,似乎没有谷歌的答案是有用的。你知道我做错了什么吗?

还有,就像我说的,我是node/mongo/mongoose/express的新手,所以如果有更好的方法来完成我的目标,请告诉我。我很感激所有的反馈。

编辑:

在Peter Lyons的解决方案之后,我在谷歌上搜索了我遇到的另一个错误,并找到了findByIdAndUpdate,它的工作方式与预期一致,并且完全符合我的期望。我仍然不确定为什么findById和findOne会给我这样的问题,我很想知道(可能需要提交一份bug报告),所以我将保留这个问题,以防其他人有答案。


共3个答案

匿名用户

简短的回答:使用mongoose.types.objectid。

Mongoose(但不是mongo)可以接受对象ID作为字符串,并为您正确地“强制转换”它们,因此只需使用:

MyClass.findById(req.params.id)

但是,需要注意的是,如果req.params.ID不是mongo ID字符串的有效格式,那么将引发一个必须捕获的异常。

因此,主要令人困惑的是,mongoose.schematypes具有只在定义mongoose模式时使用的内容,而mongoose.types具有在创建要存储在数据库中的数据对象或查询对象时使用的内容。因此mongoose.types.objectid(“51bb793aca2ab77a3200000d”)可以工作,它将为您提供一个可以存储在数据库中或在查询中使用的对象,如果给出了无效的ID字符串,它将引发异常。

findone接受一个查询对象,并将单个模型实例传递给回调。而findById实际上是findone({_id:id})的包装器(参见此处的源代码)。只需find获取一个查询对象,并将匹配模型实例的数组传递给回调。

慢慢来。这是令人困惑的,但我可以向你保证,在这一点上,你是困惑的,而不是打猫鼬的虫子。这是一个相当成熟的图书馆,但需要一些时间才能掌握其中的诀窍。

我在您的代码段中看到的另一个可疑之处是在实例化ChildClass时没有使用New。除此之外,您还需要张贴您的模式代码,以便我们帮助您跟踪剩余的任何CAST错误。

匿名用户

我遇到过这个错误,这是因为您想要在_ID字段中筛选的值不是ID格式的,一个“if”应该可以解决您的错误。

const mongoose = require('mongoose');

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

若要解决此问题,请始终验证搜索的条件值是否为有效的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
})

匿名用户

对于所有那些坚持这个问题,但仍然不能解决它的人来说:我偶然发现了同样的错误,发现_id字段是空的。

我在这里更详细地描述了它。除了将_id中的字段更改为not-ID字段之外,还没有找到解决方案,这对我来说是一个肮脏的黑客。我可能要给猫鼬报个窃听器。如有任何帮助,我们将不胜感激!

编辑:我更新了我的线程。我提交了一张罚单,他们确认了丢失的_id问题。它将在4.x.x版本中修复,该版本现在有一个候选版本可用。不建议将rc用于生产!

相关问题