什么是Mongoose错误对于路径“_id”的值XXX,对ObjectId的转换失败?

时间:2013-02-18 16:18:04

标签: mongodb mongoose

/customers/41224d776a326fb40f000001发送请求时,_id 41224d776a326fb40f000001的文档不存在,docnull,我正在返回404 1}}:

  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:对于路径“_id”的值“foo”,Cast to ObjectId失败。

那么这个错误是什么?

28 个答案:

答案 0 :(得分:144)

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.
}

答案 1 :(得分:32)

使用现有函数检查ObjectID。

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

答案 2 :(得分:11)

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

在我的申请中,我所做的是:

ObjectId.fromString( myObjectIdString );

答案 3 :(得分:3)

您还可以使用ObjectId.isValid,如下所示:

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

答案 4 :(得分:2)

如果上述解决方案对您不起作用。 检查您是否正在向 POST 路由发送 GET 请求。
对我来说就是那么简单和愚蠢。

答案 5 :(得分:2)

如果你有两条这样的不同路由,这可能是路由不匹配的情况

router.route("/order/me") //should come before the route which has been passed with params
router.route("/order/:id")

那么你必须小心地将使用参数的路线放在对我有用的常规路线之后

答案 6 :(得分:2)

截至2019年11月19日

您可以使用猫鼬版本5.7.12中的isValidObjectId(id)

https://mongoosejs.com/docs/api/mongoose.html#mongoose_Mongoose-isValidObjectId

答案 7 :(得分:2)

最近我遇到了类似的问题,并通过捕获错误以找出是否是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);
    }
});

答案 8 :(得分:2)

我添加了相同的问题
_id:在模式中为字符串。然后开始工作

答案 9 :(得分:1)

//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
}

答案 10 :(得分:1)

您可以在查询中使用每个ID之前先对其进行验证(我认为这是最佳做法),

// Assuming you are using Express, this can return 404 automatically.
app.post('/resource/:id([0-9a-f]{24})', function(req, res){
  const id = req.params.id;
  // ...
});

...或者您可以猴子修补Mongoose来忽略那些强制转换错误,而是使用字符串表示形式进行查询。您的查询当然不会找到任何东西,但是无论如何,这可能就是您想要的。

import { SchemaType }  from 'mongoose';

let patched = false;

export const queryObjectIdCastErrorHandler = {
  install,
};

/**
 * Monkey patches `mongoose.SchemaType.prototype.castForQueryWrapper` to catch
 * ObjectId cast errors and return string instead so that the query can continue
 * the execution. Since failed casts will now use a string instead of ObjectId
 * your queries will not find what they are looking for and may actually find
 * something else if you happen to have a document with this id using string
 * representation. I think this is more or less how MySQL would behave if you
 * queried a document by id and sent a string instead of a number for example.
 */
function install() {
  if (patched) {
    return;
  }

  patch();

  patched = true;
}

function patch() {
  // @ts-ignore using private api.
  const original = SchemaType.prototype.castForQueryWrapper;

  // @ts-ignore using private api.
  SchemaType.prototype.castForQueryWrapper = function () {
    try {
      return original.apply(this, arguments);
    } catch (e) {
      if ((e.message as string).startsWith('Cast to ObjectId failed')) {
        return arguments[0].val;
      }

      throw e;
    }
  };
}

答案 11 :(得分:1)

我对此有疑问,并且在没有mongoose.ObjectId(id)的情况下做了Types

答案 12 :(得分:1)

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

最好是检查有效性

答案 13 :(得分:1)

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

});

express-validator版本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);
        });

    });

});

答案 14 :(得分:0)

ObjectId由以下内容组成。

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

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

mongoose.Types.ObjectId.isValid(sample_object_id)

答案 15 :(得分:0)

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

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

答案 16 :(得分:0)

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

我喜欢反引号:     `${id}`

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

答案 17 :(得分:0)

检测并纠正ObjectID错误

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

highest_turnout

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

我希望这会有所帮助。

答案 18 :(得分:0)

如果有人碰到这个, 对我来说解决的是将需求中的单引号更改为`。

代替:

const something = require('./models/something');

使用:

const something = require(`./models/something`);

知道这听起来很有趣,但是它确实有效。

答案 19 :(得分:0)

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

答案 20 :(得分: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

答案 21 :(得分:0)

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

答案 22 :(得分:0)

当您将无效ID传递给猫鼬时会发生这种情况。因此,在使用猫鼬isValid函数

之前,请先进行检查
import mongoose from "mongoose";

// add this inside your route
if( !mongoose.Types.ObjectId.isValid(id) ) return false;

答案 23 :(得分:0)

我有同样的错误,但在与问题不同的情况下,但也许它对某人有用。

问题在于添加带扣:

错误:

    const gamesArray = [myId];

    const player = await Player.findByIdAndUpdate(req.player._id, {
         gamesId: [gamesArray]
    }, { new: true }

正确:

    const gamesArray = [myId];

    const player = await Player.findByIdAndUpdate(req.player._id, {
         gamesId: gamesArray
    }, { new: true }

答案 24 :(得分:0)

或者你可以这样做

var ObjectId = require('mongoose').Types.ObjectId; var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );

如此处所述Mongoose's find method with $or condition does not work properly

答案 25 :(得分:0)

我改编了@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);
  }
};

答案 26 :(得分:0)

在我的例子中,参数 id 的长度是 25,所以我修剪了参数 id 的第一个字符并尝试。成功了。

<块引用>

块引用

const paramId = req.params.id;
if(paramId.length === 25){
  const _id = paramId.substring(1, 25);
}

将字符串对象更改为 ObjectId 的实例 fromString() 方法不再存在。有一个新方法 createFromHexString()。

const _id = mongoose.Types.ObjectId.fromString(id); // old method not available
const _id = mongoose.Types.ObjectId.createFromHexString(id); // new method.

答案 27 :(得分:-1)

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