ข้อผิดพลาดของพังพอน Cast to ObjectId ล้มเหลวสำหรับค่า XXX ที่พา ธ “ _id” คืออะไร


122

เมื่อส่งคำขอไป/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: Cast to ObjectId ล้มเหลวสำหรับค่า "foo" ที่พา ธ "_id"

แล้วข้อผิดพลาดนี้คืออะไร?

คำตอบ:


182

findByIdวิธีการของ Mongoose จะเหวี่ยงidพารามิเตอร์เป็นประเภทของ_idฟิลด์ของโมเดลเพื่อให้สามารถค้นหาเอกสารที่ตรงกันได้อย่างถูกต้อง นี่คือ ObjectId แต่"foo"ไม่ใช่ ObjectId ที่ถูกต้องดังนั้นการร่ายจึงล้มเหลว

สิ่งนี้ไม่เกิดขึ้น41224d776a326fb40f000001เนื่องจากสตริงนั้นเป็น ObjectId ที่ถูกต้อง

วิธีหนึ่งในการแก้ไขปัญหานี้คือเพิ่มการตรวจสอบก่อนการfindByIdโทรของคุณเพื่อดูว่าidObjectId ถูกต้องหรือไม่:

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

4
@Gremo คุณสามารถเลือกประเภทเดียวที่จะใช้_idในโครงสร้างพังพอนของคุณ ใน"bla"กรณีนี้คุณจะใช้ประเภทของStringแทนค่าเริ่มต้นObjectIdและคุณไม่จำเป็นต้องเพิ่มการตรวจสอบนี้เนื่องจากสามารถส่งสิ่งใด ๆ ไปยังสตริงได้
JohnnyHK

2
ฉันเข้าใจ แต่ฉันต้องการหลีกเลี่ยงการตรวจสอบนี้ ฉันจะสร้างใหม่ObjectIdจากสตริงที่กำหนด (จากGETคำขอ) เพื่อส่งต่อไปยังfindByIdเมธอดได้อย่างไร
gremo

@ เกรโมคุณทำไม่ได้ คุณสามารถสร้าง ObjectIds จากสตริงอักขระเลขฐานสิบหก 24 ตัวเท่านั้น
JohnnyHK

1
คุณสามารถใช้ find ({_ id: yourId}, ... ) เพื่อค้นหาเอกสารด้วย id (ไม่ซ้ำกัน) นั่นและคำตอบของ JohnnyHK ในการเพิ่ม _id ลงในสคีมาของคุณ (ด้วยประเภท 'สตริง' ที่คุณต้องการ) เป็นวิธีแก้ปัญหาของคุณอย่างสมบูรณ์
Steve Hollasch

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'ตัวอย่างของคุณด้วย github.com/mongodb/js-bson/issues/106
JohnnyHK

console.log ( "ที่นี่"); ให้ฉัน = พังพอนใหม่ type.ObjectId (userId.id); console.log ("ตอนนี้ที่นี่"); // คอนโซลนี้ไม่พิมพ์ด้วยซ้ำ
yogesh agrawal

11

คุณกำลังแยกวิเคราะห์สตริงนั้นเป็นObjectIdหรือไม่?

ในใบสมัครของฉันสิ่งที่ฉันทำคือ:

ObjectId.fromString( myObjectIdString );

ใช่คุณควรเพราะคุณกำลังค้นหาประเภท ObjectId ดังนั้นจึงจำเป็นต้องใช้นักแสดง
gustavohenke

1
ลองmongoose.Types.ObjectId.
gustavohenke

1
ใช้งานได้ แต่ฉันได้รับ "ObjectId ไม่ถูกต้อง" เมื่อผ่าน "foo" แล้วจุดประสงค์ของการสร้าง ObjectId จากสตริงคืออะไรถ้ามันอาจล้มเหลว?
gremo

ตามเอกสาร MongoDB ObjectIds ต้องเป็นเลขฐานสิบหก 24 ไบต์เท่านั้น
gustavohenke

1
fromStringไม่ใช่ฟังก์ชัน
WasiF

8

ฉันมีปัญหาเดียวกันฉันเพิ่ม
_id: String. ในสคีมาจากนั้นจะเริ่มทำงาน


หนึ่งปีต่อมาสิ่งนี้ช่วยฉันได้เมื่อใช้กับ connect-mongo
Ren44

ขอบคุณที่ติดขัดในจุดเล็ก ๆ หลังจากทำงานเป็นเวลา 15 ชม.
Black Mamba

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 เป็นไปตามนี้ / 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

2

เมื่อเร็ว ๆ นี้ฉันต้องเผชิญกับสิ่งที่คล้ายกันและแก้ไขได้โดยการจับข้อผิดพลาดเพื่อดูว่าเป็นข้อผิดพลาดของพังพอน 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);
    }
});


1

ฉันไปกับการดัดแปลงโซลูชัน @gustavohenke โดยใช้ ObjectId Cast ในการลองจับที่ล้อมรอบโค้ดดั้งเดิมเพื่อใช้ประโยชน์จากความล้มเหลวของการหล่อ 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 ก่อนที่จะเรียกใช้แบบสอบถามของคุณดังนั้นแอปของคุณจะไม่หยุดทำงาน



0

วิธีที่ฉันแก้ไขปัญหานี้คือการเปลี่ยน id เป็นสตริง

ฉันชอบมันแฟนซีกับ backtick: `${id}`

สิ่งนี้ควรแก้ไขปัญหาโดยไม่มีค่าใช้จ่าย


0

ObjectId ประกอบด้วยสิ่งต่อไปนี้

  1. ค่า 4 ไบต์แทนวินาทีนับตั้งแต่ยุค Unix
  2. ค่าสุ่ม 5 ไบต์ (รหัสเครื่อง 3 ไบต์และรหัสโปรเซสเซอร์ 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

0

ฉันมีปัญหากับสิ่งนี้และแก้ไขmongoose.ObjectId(id)โดยไม่ต้องทำTypes

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.