/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
が、たとえばGET /customers/foo
を使用して、Mongooseが「フォーマット」として期待するものと一致しない場合(おそらく)、奇妙なエラーが返されます。
CastError:パス「_id」で値「foo」のObjectIdへのキャストに失敗しました。
それで、このエラーは何ですか?
MongooseのfindById
メソッドは、id
パラメーターをモデルの_id
フィールドの型にキャストして、一致するドキュメントを適切に照会できるようにします。これはObjectIdですが、"foo"
は有効なObjectIdではないため、キャストは失敗します。
この文字列は有効なObjectIdであるため、これは41224d776a326fb40f000001
では発生しません。
これを解決する1つの方法は、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');
その文字列をObjectId
として解析していますか?
ここで私のアプリケーションでは、私がやっていることは:
ObjectId.fromString( myObjectIdString );
次のようにObjectId.isValidを使用することもできます。
if (!ObjectId.isValid(userId)) return Error({ status: 422 })
追加したのと同じ問題があります
_ id:String .in schemaその後、作業を開始します
これは古い質問ですが、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);
});
});
});
//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
}
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"});
}
妥当性をチェックするのが最善です
ルートパラメーターをキャッチしている他のルートの上にルートを移動する必要がありました。
// 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);
この問題を修正する方法は、IDを文字列に変換することです
バックティックが好きです:`${id}`
これはオーバーヘッドなしで問題を解決するはずです
私は@gustavohenkeソリューションの適応に取り組み、ObjectIdキャストの失敗を検証方法として活用するために、try-catch 元のコードにラップでキャスト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);
}
};
クエリで常にmongoose.Types.ObjectId('your id')
条件を使用すると、クエリが実行される前にidフィールドが検証され、アプリがクラッシュしなくなります。
ObjectIdは、次のもので構成されます。
ObjectIdが有効かどうかを検証する正しい方法は、ObjectIdクラス自体の静的メソッドを使用することです。
mongoose.Types.ObjectId.isValid(sample_object_id)
または、これを行うことができます
var ObjectId = require('mongoose').Types.ObjectId; var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );
ここで述べたように、 $ or条件でのMongooseのfindメソッドは正しく動作しません
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("/");
}
});
});
これは私にとってはうまくいきました。他のアイテムが戻り文字列に表示され始めたら、同様の方法で削除できると思います。
これがお役に立てば幸いです。
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
誰かがこれに遭遇した場合、私にとってそれを解決したのは、requireの単一引用符から `に変更されたことです。
の代わりに:
const something = require('./models/something');
つかいます:
const something = require(`./models/something`);
面白いように聞こえますが、実際には機能します。