パス "_id"で値XXXのMongooseエラーCast to ObjectIdが失敗したのは何ですか?


122

にリクエストを送信する/customers/41224d776a326fb40f000001と、ドキュメントが_id 41224d776a326fb40f000001存在しない場合は、docnull返されます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);
    });
  };

ただし、_idMongooseが「フォーマット」として想定しているものと一致しない場合(おそらく)GET /customers/foo、奇妙なエラーが返されます。

CastError:パス "_id"の値 "foo"のObjectIdへのキャストに失敗しました。

それで、このエラーは何ですか?

回答:


182

MongooseのfindByIdメソッドは、一致するドキュメントを適切にクエリできるようidに、モデルの_idフィールドのタイプにパラメーターをキャストします。これはObjectIdですが"foo"、有効なObjectIdではないため、キャストは失敗します。

41224d776a326fb40f000001その文字列は有効なObjectId であるため、これは起こりません。

これを解決する1つの方法は、findById呼び出しの前にid、有効なObjectIdかどうかを確認するチェックを追加することです。

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

4
@Gremo _idMongooseスキーマで使用するタイプを1つだけ選択できます。では"bla"場合、あなたはのタイプ使用するStringデフォルトの代わりにObjectId、あなたは何を文字列にキャストできるよう、このチェックを追加する必要はありません。
JohnnyHK

2
わかりましたが、このチェックは避けたいです。メソッドに渡すために、ObjectIdGETリクエストから)指定された文字列から新規作成するにはどうすればよいfindByIdですか?
gremo

@Gremoできません。24桁の16進文字列からのみObjectIdを構築できます。
JohnnyHK

1
find({_ id:yourId}、...)を使用して、その(一意の)IDを持つドキュメントをクエリできます。それと、スキーマに_idを追加するためのJohnnyHKの答え(目的の「文字列」タイプを使用)が問題の完全な解決策です。
Steve Hollasch、2014年

1
最近では、12文字の文字列をObjectIdにキャストすることもできます。ObjectId("000000000000") --> 303030303030303030303030
Dan Ross、

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

console.log( "こちら"); let i = new mongoose.Types.ObjectId(userId.id); console.log( "now here"); //このコンソールは印刷さえしていません
yogesh agrawal

11

その文字列を次のように解析していますObjectIdか?

ここで私のアプリケーションでは、私がしていることは:

ObjectId.fromString( myObjectIdString );

はい、する必要があります。ObjectIdタイプをクエリしているため、キャストが必要だからです。
gustavohenke 2013

1
お試しくださいmongoose.Types.ObjectId
gustavohenke 2013

1
動作しますが、 "foo"を渡すと "Invalid ObjectId"が返されます。では、文字列からObjectIdを作成する意味は何ですか?
グレモ

MongoDBのドキュメントに従って、ObjectIdsは24桁の16進バイトのみである必要があります。
gustavohenke 2013

1
fromStringは関数ではありません
WasiF

8

同じ問題があり、
_id:String .inスキーマを追加すると、作業が開始されます


1年後、connect-mongoと一緒に使用するときにこれが私を救いました
Ren44

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

それだけでした。1時間前にあなたの答えを見つけられたらいいのに。乾杯!
Sodbileg Gansukh

これでうまくいきました。このエラーの背後にある理由に興味があります。通常のルートの下にルートを移動すると、エラーが解消された理由を説明していただけますか?
Vishwak

これも私に働きました。/ test / createは、この/ test /:idをid = createで満たすように見えます。また、文字列を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スキーマに追加する必要があり、その後すべてが正常に機能しました。


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パッケージを使用してリクエストパラメータを確認することもできます

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

    });

});

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. Unixエポックからの秒数を表す4バイトの値
  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エラーの検出と修正mongoose

を使用してアイテムを削除しようとすると、この問題に遭遇し、同じエラーが発生しました。返された文字列を確認したところ、返された文字列の中に余分なスペースがあり、エラーが発生しました。そこで、ここで提供されたいくつかの回答を適用して、誤った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として
取得しました
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.