Lỗi Mongoose Truyền tới ObjectId không thành công cho giá trị XXX tại đường dẫn “_id” là gì?


122

Khi gửi một yêu cầu đến /customers/41224d776a326fb40f000001và một tài liệu với _id 41224d776a326fb40f000001không tồn tại, docnullvà tôi trở lại một 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);
    });
  };

Tuy nhiên, khi _idkhông khớp với những gì Mongoose mong đợi là "định dạng" (tôi cho là), ví dụ như với GET /customers/foomột lỗi lạ được trả về:

CastError: Không thể truyền tới ObjectId cho giá trị "foo" tại đường dẫn "_id".

Vậy đây là lỗi gì?

Câu trả lời:


182

findByIdPhương thức của Mongoose truyền idtham số thành loại trường của mô hình _idđể nó có thể truy vấn đúng tài liệu phù hợp. Đây là một ObjectId nhưng "foo"không phải là một ObjectId hợp lệ nên việc ép kiểu không thành công.

Điều này không xảy ra với 41224d776a326fb40f000001vì chuỗi đó là một ObjectId hợp lệ.

Một cách để giải quyết vấn đề này là thêm kiểm tra trước findByIdcuộc gọi của bạn để xem có phải idlà ObjectId hợp lệ hay không:

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

4
@Gremo Bạn chỉ có thể chọn một loại để sử dụng _idtrong lược đồ Mongoose của mình. Trong "bla"trường hợp bạn sử dụng kiểu Stringthay vì kiểu mặc định ObjectIdvà bạn sẽ không cần thêm dấu kiểm này vì mọi thứ đều có thể được truyền thành chuỗi.
JohnnyHK

2
Tôi hiểu, nhưng tôi muốn tránh kiểm tra này. Làm cách nào để tạo một chuỗi mới ObjectIdtừ một chuỗi đã cho (từ GETyêu cầu) để chuyển nó đến findByIdphương thức?
gremo

@Gremo Bạn không thể. Bạn chỉ có thể tạo các ObjectIds từ 24 chuỗi ký tự hex.
JohnnyHK

1
Bạn chỉ có thể sử dụng find ({_ id: yourId}, ...) để truy vấn tài liệu có id (duy nhất) đó. Điều đó và câu trả lời của JohnnyHK để thêm _id vào lược đồ của bạn (với loại 'chuỗi' mong muốn của bạn) là giải pháp đầy đủ cho vấn đề của bạn.
Steve Hollasch

1
Ngày nay, 12 chuỗi ký tự cũng có thể được truyền sang một ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Dan Ross

50

Sử dụng các chức năng hiện có để kiểm tra ObjectID.

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

15
Cẩn thận khi sử dụng phương thức đó vì nó có hành vi kỳ lạ là coi bất kỳ chuỗi 12 byte nào là hợp lệ. Vì vậy, nó thậm chí trả về true cho 'your id here'ví dụ của bạn . github.com/mongodb/js-bson/issues/106
JohnnyHK

console.log ("tại đây"); let i = new mongoose.Types.ObjectId (userId.id); console.log ("bây giờ ở đây"); // bảng điều khiển này thậm chí không in được
yogesh agrawal

11

Bạn có đang phân tích chuỗi đó là ObjectId?

Ở đây trong ứng dụng của tôi, những gì tôi làm là:

ObjectId.fromString( myObjectIdString );

Có, bạn nên làm vậy, vì bạn đang truy vấn một kiểu ObjectId, vì vậy việc truyền là cần thiết.
gustavohenke

1
Hãy thử mongoose.Types.ObjectId.
gustavohenke

1
Hoạt động, nhưng tôi nhận được "ObjectId không hợp lệ" khi chuyển "foo". Vậy mục đích của việc tạo ObjectId từ một chuỗi là gì, nếu nó có thể bị lỗi?
gremo

Theo tài liệu MongoDB, ObjectIds chỉ được 24 byte thập lục phân.
gustavohenke

1
fromStringkhông phải là một chức năng
Wasif

8

Tôi gặp vấn đề tương tự, tôi thêm
_id: String .in giản đồ thì nó bắt đầu hoạt động


một năm sau này đã cứu tôi khi sử dụng với kết nối-Mongo
Ren44

Cảm ơn bạn đã bị mắc kẹt ở một điểm nhỏ sau khi làm việc trong 15 giờ liên tục.
Black Mamba

8

Tôi đã phải di chuyển các tuyến đường của mình trên các tuyến đường khác đang bắt các thông số tuyến đường:

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

Điều đó là vậy đó. Tôi ước tôi tìm thấy câu trả lời của bạn một giờ trước. Chúc mừng!
Sodbileg Gansukh

Điều này đã làm việc cho tôi. Tôi tò mò lý do đằng sau lỗi này. Xin ông vui lòng giải thích việc di chuyển tuyến đường bên dưới các tuyến đường thông thường đã khiến lỗi biến mất như thế nào?
Vishwak

Điều này đã làm việc với tôi. Có vẻ như / test / create đáp ứng điều này / test /: id với id = create. và chuỗi không thể được truyền thành_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"});
        }

tốt nhất là kiểm tra tính hợp lệ


3

Trong trường hợp của tôi, tôi phải thêm _id: Objectvào Lược đồ của mình, và sau đó mọi thứ hoạt động tốt.


2

Bạn cũng có thể sử dụng ObjectId.isValid như sau:

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

1
ReferenceError: ObjectId không được định nghĩa
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
}

Có những câu trả lời khác cung cấp câu hỏi của OP, và chúng đã được đăng cách đây nhiều năm. Khi đăng câu trả lời, vui lòng đảm bảo bạn thêm giải pháp mới hoặc giải thích về cơ bản tốt hơn, đặc biệt là khi trả lời các câu hỏi cũ hơn. Các câu trả lời chỉ có mã được coi là chất lượng thấp: hãy đảm bảo cung cấp lời giải thích mã của bạn hoạt động như thế nào và cách nó giải quyết vấn đề.
help-info.de

2

Gần đây, tôi đã phải đối mặt với một điều gì đó tương tự và đã giải quyết nó bằng cách bắt lỗi để tìm xem đó có phải là lỗi Mongoose ObjectId hay không.

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

Tôi đã đi với một bản điều chỉnh của giải pháp @gustavohenke, triển khai ép kiểu ObjectId trong một thử nghiệm được bao bọc xung quanh mã gốc để tận dụng sự thất bại của việc truyền ObjectId như một phương pháp xác thực.

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
Điều này sẽ rất hay khi sử dụng, nhưng fromString () không còn tồn tại nữa: github.com/Automattic/mongoose/issues/1890
Brent Washburne

1

Đây là một câu hỏi cũ nhưng bạn cũng có thể sử dụng gói express-validator để kiểm tra các thông số yêu cầu

express-validator phiên bản 4 (mới nhất):

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 phiên bản 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

Luôn sử dụng mongoose.Types.ObjectId('your id')cho các điều kiện trong truy vấn của bạn, nó sẽ xác thực trường id trước khi chạy truy vấn của bạn, do đó ứng dụng của bạn sẽ không bị lỗi.



0

Cách tôi khắc phục sự cố này là chuyển đổi id thành một chuỗi

tôi thích nó lạ mắt với backtick: `${id}`

điều này sẽ khắc phục sự cố mà không có chi phí


0

ObjectId bao gồm những thứ sau.

  1. giá trị 4 byte đại diện cho số giây kể từ kỷ nguyên Unix
  2. giá trị ngẫu nhiên 5 byte (ID máy 3 byte và id bộ xử lý 2 byte)
  3. một bộ đếm 3 byte, bắt đầu bằng một giá trị ngẫu nhiên.

Cách đúng để xác thực nếu objectId hợp lệ là sử dụng phương thức tĩnh từ chính lớp ObjectId.

mongoose.Types.ObjectId.isValid (sample_object_id)


0

Truyền chuỗi tới 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

Phát hiện và sửa lỗi ObjectID

Tôi đã gặp phải sự cố này khi cố gắng xóa một mục bằng mongoose và gặp lỗi tương tự. Sau khi xem qua chuỗi trả về, tôi thấy có một số khoảng trắng thừa bên trong chuỗi trả về gây ra lỗi cho tôi. Vì vậy, tôi đã áp dụng một số câu trả lời được cung cấp ở đây để phát hiện id sai sau đó loại bỏ các khoảng trắng thừa khỏi chuỗi. Đây là mã đã làm việc cho tôi để giải quyết vấn đề cuối cùng.

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

Điều này đã hiệu quả với tôi và tôi giả sử nếu các mục khác bắt đầu xuất hiện trong chuỗi trả về, chúng có thể bị xóa theo cách tương tự.

Tôi hi vọng cái này giúp được.


0

Tôi đã khắc phục sự cố này khi thay đổi thứ tự của các tuyến đường.


Đây dường như không phải là một câu trả lời. Tốt nhất, đó là một bình luận.
MS

Điều này phù hợp với tôi, tôi có 2 tuyến đường cho blog: '/ blogs / create' và 'blogs /: id'. Và cái sau đến trước theo thứ tự của các tuyến đường. Vì vậy, khi tôi truy cập '/ blog / create' mongoose đã lấy 'create' làm id
Wyrone

0

Tôi đã gặp vấn đề với điều này và cố định làm mongoose.ObjectId(id)mà khôngTypes

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.