首页 > 解决方案 > 对于模型的路径“_id”处的值,转换为 ObjectId 失败

问题描述

错误是

Cast to ObjectId failed for value "hist" at path "_id" for model "books"

你好呀!

问题:

我正在尝试在另一个模型中使用其他模型,确切地说,一个模型中有两个模型。型号如下

models: {
   'Professor'
   'Book'
}

我想使用另一个名为 checkoutHistory 的猫鼬模型中的模式。

我的理解是,为了做到这一点,我需要这样做

{类型:猫鼬.Schema.Types.ObjectID,参考:'书'}

这是我要从中创建和检索数据的模型。

const  mongoose = require('mongoose');
const Schema = mongoose.Schema;


const checkoutHistory = new Schema({
    book: { type: mongoose.Schema.Types.ObjectId, ref: 'books',required: true },
    checkoutCopiesNum: {type: Number, required: true},
    profChosen: { type: mongoose.Schema.Types.ObjectId, ref: 'prof', required: true },
    dueDate: {type: String, required: true}

})



/* Exporting it as a mongoose model so that it can be put into the data base */
module.exports = mongoose.model('checkoutHist', checkoutHistory)

这适用于我使用此模型创建文档时。像这样...

const checkoutHistoryMiddle = (req, res, next) => {
    try {
        //get the body of the request
        const body = req.body
    
        //check for data
        if(!body){
            return res.status(400).json({
                success: false,
                error: 'no body given'
            })
        }

        const history = new CheckoutHist(body)


        history.save().then(() => next()).catch(error => {
            return res.status(400).json({
                success: false, 
                message: error,
                msg: "checkout save failed"

            })
        })




    } catch (error) {
        res.status(400).json({
            success: false,
            message: error,
            msg: "checkoutHist failed"
        })
    }



}

所以上面的代码会将一个新的历史对象保存到数据库中,这目前工作正常。

这是我们进入实际问题的地方。由于上述错误,我无法从 mongo 数据库中检索这些文档。我正确设置了路线:

router.get('/book/hist', BookCtrl.getCheckoutHistory)


getCheckoutHistory = async (req, res) => {
    try {
        return res.status(200).json({success: true, msg:"success"})
    } catch (err) {
        return res.status(400).json({success: false, msg:"failed"})
    }
    

    // await CheckHist.find({}, (err, hist) => {
    //     if (err) {
    //         return res.status(400).json({ success: false, error: err })
    //     }

    //     if (!hist) {
    //         return res
    //             .status(404)
    //             .json({ success: false, error: `History not found` })
    //     }
    //     return res.status(200).json({ success: true, data: hist })
    // }).catch(err => console.log(err))

}

我注释掉了代码以显示我正在尝试做的事情,并强调无论在这个函数中做了什么,它都不会运行。

现在这个错误特别奇怪的是它指向文件中与我在这里所做的事情无关的部分是错误:

at getBookById (/Users/devintripp/Desktop/unt-library-system/server/controllers/book-ctrl.js:376:13)

这有什么奇怪的,当我访问 /book/hist 端点时,我实际上并没有在任何地方调用这个函数。这是这个函数的作用:

getBookById = async (req, res) => {
    await Book.findOne({ _id: req.params.id }, (err, book) => {
        if (err) {
            return res.status(400).json({ success: false, error: err })
        }

        if (!book) {
            return res
                .status(404)
                .json({ success: false, error: `Book not found` })
        }
        return res.status(200).json({ success: true, data: book })
    }).catch(err => console.log(err))
}

很奇怪。因为我正在访问这样的端点。

useEffect( () => {
        const getHistory = async () => {
            // await Axios.get('http://localhost:8174/api/book/hist').then(bookHist => {
          
            //     console.log(bookHist.data.data)

           
            // })

            api.getCheckoutHist().then(hist => {
                console.log(hist)
            })
        }

        getHistory()
    }, [])

api.getCheckoutHist()做同样的事情Axios.get并产生同样的错误,我把它放在那里向你展示我正在访问的端点。访问 findById 函数的端点位于不同的字符串 http://localhost:8174/api/book/:id

这是我得到的完整错误:

CastError: Cast to ObjectId failed for value "hist" at path "_id" for model "books"
    at model.Query.exec (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/query.js:4358:21)
    at model.Query.Query.catch (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/query.js:4464:15)
    at getBookById (/Users/devintripp/Desktop/unt-library-system/server/controllers/book-ctrl.js:376:13)
    at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
    at /Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:281:22
    at param (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:354:14)
    at param (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:410:3)
    at next (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:275:10)
    at Function.handle (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:174:3)
    at router (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as handle_request] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/Users/devintripp/Desktop/unt-library-system/server/node_modules/express/lib/router/index.js:317:13) {
  messageFormat: undefined,
  stringValue: '"hist"',
  kind: 'ObjectId',
  value: 'hist',
  path: '_id',
  reason: Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters
      at new ObjectID (/Users/devintripp/Desktop/unt-library-system/server/node_modules/bson/lib/bson/objectid.js:59:11)
      at castObjectId (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/cast/objectid.js:25:12)
      at ObjectId.cast (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/schema/objectid.js:279:12)
      at ObjectId.SchemaType.applySetters (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/schematype.js:1110:12)
      at ObjectId.SchemaType._castForQuery (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/schematype.js:1545:15)
      at ObjectId.SchemaType.castForQuery (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/schematype.js:1535:15)
      at ObjectId.SchemaType.castForQueryWrapper (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/schematype.js:1512:20)
      at cast (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/cast.js:331:32)
      at model.Query.Query.cast (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/query.js:4759:12)
      at model.Query.Query._castConditions (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/query.js:1841:10)
      at model.Query.<anonymous> (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/query.js:2098:8)
      at model.Query._wrappedThunk [as _findOne] (/Users/devintripp/Desktop/unt-library-system/server/node_modules/mongoose/lib/helpers/query/wrapThunk.js:16:8)
      at /Users/devintripp/Desktop/unt-library-system/server/node_modules/kareem/index.js:370:33
      at processTicksAndRejections (internal/process/task_queues.js:75:11)
}

我希望你能理解我的困惑,也许让我了解这里到底发生了什么,我不明白任何帮助表示赞赏。

标签: node.jsreactjsmongodbmongoose

解决方案


您没有向我们展示您为您的应用定义的其他路线:

router.get('/book/hist', BookCtrl.getCheckoutHistory)

但我可以打赌你的router.get('/book/:id', ....)路线是 BEFORE router.get('/book/hist', ...)。正确的?

所以当你请求 时.../api/book/hist,猜猜谁在那里拦截它?这家伙/book/:id。它假设这hist是一个书的ID。然后它调用getBookById,它运行

await Book.findOne({ _id: req.params.id }, (err, book) => {

它试图转换hist为 ObjectID 并且不能。

所以放在router.get('/book/hist', BookCtrl.getCheckoutHistory)之前router.get('/book/:id', ....)


在 express 中声明路线真的不是很多。但是,您应该注意一些问题。这篇文章非常简短但内容丰富,您当然应该利用它。

至于您关于“在同一个路由文件中具有两个 findById 函数并转到两个单独的 [sic] 文档”的其他问题,我认为它没有任何问题。只要他们为他们定义了两条单独的路线。例如:

router.get('/profs/:profid', ProfCtrl.findProfById);
router.get('/admins/:adminid', AdminCtrl.findAdminById);

这是一种完全有效的方法。


推荐阅读