什么是Mongoose错误对于path“_id”中的值XXX,转换为ObjectId失败?
当向/customers/41224d776a326fb40f000001
发送请求并且_id
41224d776a326fb40f000001
文档不存在时, doc
为null
并且返回404
:
Controller.prototype.show = function(id, res) { this.model.findById(id, function(err, doc) { if (err) { throw err; } if (!doc) { res.send(404); } return res.send(doc); }); };
然而,当_id
不匹配Mongoose所期望的“格式”(我想)例如GET /customers/foo
会返回一个奇怪的错误:
CastError:在path“_id”上投射到ObjectId的值“foo”失败。
那么这个错误是什么?
Mongoose的findById
方法将id
参数转换为模型_id
字段的types,以便它可以正确查询匹配的文档。 这是一个ObjectId,但"foo"
不是一个有效的ObjectId,因此转换失败。
这不会发生41224d776a326fb40f000001
因为该string是一个有效的ObjectId。
解决这个问题的一个方法是在findById
调用之前添加一个检查来查看id
是否是一个有效的ObjectId或者不是这样:
if (id.match(/^[0-9a-fA-F]{24}$/)) { // Yes, it's a valid ObjectId, proceed with `findById` call. }
使用现有的函数来检查ObjectID。
var mongoose = require('mongoose'); mongoose.Types.ObjectId.isValid('your id here');
你parsing那个string为ObjectId
?
在我的应用程序中,我所做的是:
ObjectId.fromString( myObjectIdString );
你也可以像下面这样使用ObjectId.isValid:
if (!ObjectId.isValid(userId)) return Error({ status: 422 })
我采用了@gustavohenke解决scheme的一种改进, 在原始代码中包装的try-catch中实现强制转换ObjectId,以利用ObjectId强制转换作为validation方法的失败。
Controller.prototype.show = function(id, res) { try { var _id = mongoose.Types.ObjectId.fromString(id); // the original code stays the same, with _id instead of id: this.model.findById(_id, function(err, doc) { if (err) { throw err; } if (!doc) { res.send(404); } return res.send(doc); }); } catch (err) { res.json(404, err); } };
或者你可以做到这一点
var ObjectId = require('mongoose').Types.ObjectId; var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );
就像这里提到的Mongoose的$或者condition的find方法不能正常工作
这是一个老问题,但你也可以使用express-validator包来检查请求参数
express-validator版本4(最新):
validator = require('express-validator/check'); app.get('/show/:id', [ validator.param('id').isMongoId().trim() ], function(req, res) { // validation result var errors = validator.validationResult(req); // check if there are errors if ( !errors.isEmpty() ) { return res.send('404'); } // else model.findById(req.params.id, function(err, doc) { return res.send(doc); }); });
expressionvalidation器版本3:
var expressValidator = require('express-validator'); app.use(expressValidator(middlewareOptions)); app.get('/show/:id', function(req, res, next) { req.checkParams('id').isMongoId(); // validation result req.getValidationResult().then(function(result) { // check if there are errors if ( !result.isEmpty() ) { return res.send('404'); } // else model.findById(req.params.id, function(err, doc) { return res.send(doc); }); }); });