Mongoose:CastError:对于路径"_id"的值"[object Object]",转换为ObjectId失败

jmb*_*mer 52 mongoose mongodb node.js

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

TypeError:Object {}没有方法'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);
  });
});
Run Code Online (Sandbox Code Playgroud)

如果我使用路径"/ myClass/51c35e5ced18cb901d000001/childClass/create"执行此代码,则这是代码的输出:

错误:CastError:对于路径"_id"{"path":"51c35e5ced18cb901d000001","instance":"ObjectID","validators":[],"setters":的值"[object Object]",Cast to ObjectId失败], "吸气剂":[], "_索引":空}

我尝试过使用findOne并传入{_id:id},但这似乎正是findById所做的.我已经尝试过在其他网站上列出的ObjectId的不同类.我试过调用ObjectId()就像一个函数而不是一个构造函数,并返回undefined.在这一点上,我已经没有想法,谷歌搜索答案似乎没有帮助.关于我做错了什么的任何想法?

另外,就像我说的,我是node/Mongo/Mongoose/Express的新手,所以如果有更好的方法来实现我的目标,请告诉我.我感谢所有的反馈.

编辑:

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

Pet*_*ons 63

简短回答:使用mongoose.Types.ObjectId.

Mongoose(但不是mongo)可以接受对象ID作为字符串并为你正确地"强制"它们,所以只需使用:

MyClass.findById(req.params.id)
Run Code Online (Sandbox Code Playgroud)

但是,需要注意的是,如果req.params.id不是mongo ID字符串的有效格式,则会抛出必须捕获的异常.

因此,要理解的主要问题是,mongoose.SchemaTypes只有在定义mongoose模式时才使用mongoose.Types的东西,以及在创建要存储在数据库或查询对象中的数据对象时使用的东西.所以mongoose.Types.ObjectId("51bb793aca2ab77a3200000d")工作,将为您提供一个可以存储在数据库中或在查询中使用的对象,如果给出一个无效的ID字符串,将抛出异常.

findOne获取查询对象并将单个模型实例传递给回调.并且findById字面上是一个包装器findOne({_id: id})(请参阅此处的源代码).只需find获取一个查询对象,并将匹配模型实例的数组传递给回调.

慢慢来吧.这令人困惑,但我可以保证你会感到困惑,而不是在猫鼬中遇到错误.它是一个非常成熟的库,但需要一些时间来掌握它.

我在你的代码片段中看到的另一个可疑的东西是new在实例化时不使用ChildClass.除此之外,您还需要发布架构代码,以便我们帮助您解决任何剩余的CastErrors.


gsa*_*edo 28

我遇到了这个错误,那是因为你要在_id字段中过滤的值不是ID格式,一个"if"应该解决这个问题.

const mongoose = require('mongoose');

console.log(mongoose.Types.ObjectId.isValid('53cb6b9b4f4ddef1ad47f943'));
// true
console.log(mongoose.Types.ObjectId.isValid('whatever'));
// false
Run Code Online (Sandbox Code Playgroud)

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

  • 正确的。我正在测试一个带有 `findById` 的 `GET` 用户的端点,结果 id 参数必须是 12 位,否则 mongoose 将无法转换。我使用的是随机短数字。 (3认同)

Ste*_*ack 5

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

在这里更详细地描述了它。除了将字段更改_id为非 ID 字段之外,仍然没有找到解决方案,这对我来说是一个肮脏的黑客。我可能会为猫鼬提交错误报告。任何帮助,将不胜感激!

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