在路径“ _id”中,值XXX的猫鼬错误转换为ObjectId失败了吗?


122

当向发送请求到/customers/41224d776a326fb40f000001和文档_id 41224d776a326fb40f000001不存在时,docis,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与猫鼬期望的“格式”(我想)不匹配时,例如GET /customers/foo返回一个奇怪的错误:

CastError:在路径“ _id”处,对于值“ foo”的转换为ObjectId失败。

那么这是什么错误呢?

Answers:


182

Mongoose的findById方法将id参数转换为模型_id字段的类型,以便它可以正确查询匹配的文档。这是一个ObjectId,但"foo"不是有效的ObjectId,因此强制转换失败。

不会发生这种情况,41224d776a326fb40f000001因为该字符串是有效的ObjectId。

解决此问题的一种方法是在findById调用之前添加检查,以查看是否id为有效的ObjectId,如下所示:

if (id.match(/^[0-9a-fA-F]{24}$/)) {
  // Yes, it's a valid ObjectId, proceed with `findById` call.
}

4
@Gremo您只能选择一种_id在Mongoose模式中使用的类型。在这种"bla"情况下,您将使用类型String而不是默认类型,ObjectId并且您无需添加此检查,因为可以将任何内容强制转换为字符串。
JohnnyHK

2
我了解,但我想避免进行此检查。如何ObjectId从给定的字符串(从GET请求)创建一个新的并将其传递给findById方法?
gremo

@Gremo你不能。您只能从24个十六进制字符串构造ObjectId。
JohnnyHK

1
您可以只使用find({_ id:yourId},...)来查询具有该(唯一)id的文档。这样,JohnnyHK的答案就可以在您的模式中添加_id(具有所需的“字符串”类型),从而完全解决了您的问题。
Steve Hollasch 2014年

1
如今,也可以将12个字符串转换为ObjectId。ObjectId("000000000000") --> 303030303030303030303030
丹·罗斯

50

使用现有功能检查ObjectID。

var mongoose = require('mongoose');
mongoose.Types.ObjectId.isValid('your id here');

15
谨慎使用该方法,因为它具有将任何12字节字符串视为有效的奇怪行为。因此,对于您的'your id here'示例,它甚至返回true 。 github.com/mongodb/js-bson/issues/106
JohnnyHK,2015年

console.log(“ here”); 让我=新的mongoose.Types.ObjectId(userId.id); console.log(“现在在这里”); //此控制台甚至无法打印
约杰什阿格拉瓦尔

11

您是否将该字符串解析为ObjectId

在我的应用程序中,我要做的是:

ObjectId.fromString( myObjectIdString );

是的,您应该这样做,因为要查询的是ObjectId类型,因此需要强制类型转换。
gustavohenke

1
尝试mongoose.Types.ObjectId
gustavohenke

1
可以,但是传递“ foo”时出现“ Invalid ObjectId”。那么,如果可能失败,从字符串创建ObjectId有什么意义呢?
gremo

根据MongoDB文档,ObjectId必须仅是24个十六进制字节。
gustavohenke

1
fromString不是功能
WasiF

8

我在添加
_id时遇到了同样的问题:String .in schema然后它开始工作


一年后,这在与connect-mongo一起使用时为我节省了
精力

谢谢。您连续工作15个小时后被困在一个小地方。
黑曼巴舞

8

我必须将自己的路线移到其他正在捕捉路线参数的路线上:

// require express and express router

const express = require("express");
const router = express.Router();

// move this `/post/like` route on top

router.put("/post/like", requireSignin, like);

// keep the route with route parameter `/:postId` below regular routes

router.get("/post/:postId", singlePost);

就是这样 希望一个小时前找到您的答案。干杯!
Sodbileg Gansukh

这对我有用。我很好奇这个错误的原因。您能否解释一下将路线移至常规路线下方是如何导致错误消失的?
Vishwak

这也为我工作。看起来/ test / create满足id / create的/ test /:id。并且不能将字符串强制转换为to_id。
kaila88

4
 if(mongoose.Types.ObjectId.isValid(userId.id)) {
        User.findById(userId.id,function (err, doc) {
            if(err) {
                reject(err);
            } else if(doc) {
                resolve({success:true,data:doc});
            } else {
                reject({success:false,data:"no data exist for this id"})

            }
        });
        } else {
            reject({success:"false",data:"Please provide correct id"});
        }

最好是检查有效性


3

就我而言,我必须添加_id: Object到Schema中,然后一切正常。


2

您还可以像下面这样使用ObjectId.isValid:

if (!ObjectId.isValid(userId)) return Error({ status: 422 })

1
ReferenceError:未定义ObjectId
torbenrudgaard

2
//Use following to check if the id is a valid ObjectId?

var valid = mongoose.Types.ObjectId.isValid(req.params.id);
if(valid)
{
  //process your code here
} else {
  //the id is not a valid ObjectId
}

还提供了OP的问题的其他答案,并且这些答案已在多年前发布。发布答案时,请确保添加新的解决方案或实质上更好的解释,尤其是在回答较旧的问题时。仅代码答案被认为是低质量的:确保提供解释代码的作用以及如何解决问题。
help-info.de


1

我对@gustavohenke解决方案进行了改编,在围绕原始代码的try-catch中实现了强制转换ObjectId,以利用ObjectId强制转换的失败作为验证方法。

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

1
这本来很好用,但是fromString()不再存在:github.com/Automattic/mongoose/issues/1890
Brent Washburne

1

这是一个老问题,但是您也可以使用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);
    });

});

快速验证器版本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);
        });

    });

});

1

始终mongoose.Types.ObjectId('your id')在查询中使用条件,它将在运行查询之前验证id字段,因此您的应用不会崩溃。


1

最近,我遇到了类似的问题,并通过捕获错误以找出是否是Mongoose ObjectId错误来解决了该问题。

app.get("/:userId", (req, res, next) => {
    try {
        // query and other code here
    } catch (err) {
        if (err.kind === "ObjectId") {
            return res.status(404).json({
                errors: [
                    {
                        msg: "User not found",
                        status: "404",
                    },
                ],
            });
        }
        next(err);
    }
});


0

我解决此问题的方法是将id转换为字符串

我喜欢花哨的背景: `${id}`

这应该可以解决此问题,而不会产生开销


0

ObjectId由以下内容组成。

  1. 一个4字节的值,表示自Unix时代以来的秒数
  2. 5字节的随机值(机器ID 3字节,处理器ID 2字节)
  3. 从随机值开始的3字节计数器。

验证objectId是否有效的正确方法是使用ObjectId类本身的静态方法。

mongoose.Types.ObjectId.isValid(sample_object_id)


0

将字串转换为ObjectId

import mongoose from "mongoose"; // ES6 or above
const mongoose = require('mongoose'); // ES5 or below

let userid = _id
console.log(mongoose.Types.ObjectId(userid)) //5c516fae4e6a1c1cfce18d77

0

检测并纠正ObjectID错误

当我尝试使用猫鼬删除项目时遇到了同样的错误,我偶然发现了这个问题。查看返回字符串后,我发现返回的字符串内还有一些多余的空格,这对我造成了错误。因此,我应用了此处提供的一些答案来检测错误的ID,然后从字符串中删除多余的空格。这是对我有用的代码,可以最终解决该问题。

const mongoose = require("mongoose");
mongoose.set('useFindAndModify', false);  //was set due to DeprecationWarning: Mongoose: `findOneAndUpdate()` and `findOneAndDelete()` without the `useFindAndModify`



app.post("/delete", function(req, res){
  let checkedItem = req.body.deleteItem;
  if (!mongoose.Types.ObjectId.isValid(checkedItem)) {
    checkedItem = checkedItem.replace(/\s/g, '');
  }

  Item.findByIdAndRemove(checkedItem, function(err) {
    if (!err) {
      console.log("Successfully Deleted " + checkedItem);
        res.redirect("/");
      }
    });
});

这对我有用,我假设如果其他项目开始出现在返回字符串中,则可以通过类似的方式将其删除。

我希望这有帮助。


0

我已解决了更改路线顺序的问题。


这似乎不是答案。充其量只是一条评论。
MS

这对我很有效,我有2条关于博客的路线:“ / blogs / create”和“ blogs /:id”。后者按路线顺序排在第一位。所以当我去'/ blogs / create'时,猫鼬把'create'作为id
Wyrone
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.