我是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报告),所以我将保留这个问题,以防其他人有答案。
简短的回答:使用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用于生产!