Що таке Мангузова помилка 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не відповідає тому, що Мангуст очікує як "формат" (я вважаю), наприклад, із GET /customers/fooдивною помилкою повертається:

CastError: Cast to ObjectId не вдалося для значення "foo" на шляху "_id".

То в чому ця помилка?

Відповіді:


182

Mongoose в findByIdметоді відкидає idпараметр типу моделі _idполя , так що він може правильно запит для узгодження дока. Це ObjectId, але "foo"не є дійсним ObjectId, тому команда не працює.

Цього не відбувається, 41224d776a326fb40f000001тому що цей рядок є дійсним ObjectId.

Один із способів вирішити це - додати чек перед вашим findByIdдзвінком, щоб побачити, чи idдійсний ObjectId чи не так:

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

4
@Gremo Ви можете вибрати лише один тип, який буде використовуватись _idу вашій схемі Mongoose. У "bla"випадку, якщо ви використовуєте тип Stringзамість за замовчуванням, ObjectIdі вам не потрібно буде додавати цей чек, оскільки все може бути передано до рядка.
JohnnyHK

2
Я розумію, але я хотів би уникнути цієї перевірки. Як я можу створити новий ObjectIdіз заданого рядка (із GETзапиту) для передачі його findByIdметоду?
gremo

@Gremo Ви не можете. Ви можете сконструювати ObjectIds лише з 24 шістнадцяткових символьних рядків.
JohnnyHK

1
Ви можете просто використати find ({_ id: yourId}, ...) для запиту документа з цим (унікальним) ідентифікатором. Це, і відповідь JohnnyHK додати _id до вашої схеми (з потрібним типом "string") - це повне рішення вашої проблеми.
Стів Холлаш

1
У цей день 12 рядків символів також можуть бути передані до ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Ден Росс

50

Використовуйте існуючі функції для перевірки ObjectID.

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

15
Обережно, використовуючи цей метод, оскільки він допитливо поводиться з будь-яким 12-байтовим рядком як дійсним. Тож це навіть повертає істину для вашого 'your id here'прикладу. github.com/mongodb/js-bson/isissue/106
JohnnyHK

console.log ("тут"); нехай i = new mongoose.Types.ObjectId (userId.id); console.log ("зараз тут"); // ця консоль навіть не друкується
йогеш агравал

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 .in, тоді вона починає працювати


через рік це врятувало мене під час використання з 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);

Це було все. Я б хотів, щоб я знайшов вашу відповідь годину тому. Ура!
Содбілег Гансух

Це працювало для мене. Мені цікаво причина цієї помилки. Чи можете ви пояснити, як переміщення маршруту нижче звичайних маршрутів призвело до відмови помилки?
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
}

Є й інші відповіді, які забезпечують питання ОП, і вони були опубліковані багато років тому. Опублікувавши відповідь, будь ласка, переконайтесь, що ви додали або нове рішення, або істотно краще пояснення, особливо, відповідаючи на старі питання. Відповіді, що стосуються лише коду, вважаються низькою якістю: обов’язково надайте пояснення, що робить ваш код і як він вирішує проблему.
help-info.de

2

Нещодавно я зіткнувся з чимось подібним і вирішив це, ввівши помилку, щоб з’ясувати, чи це помилка 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);
    }
});


1

Я пішов з адаптацією рішення @gustavohenke, реалізуючи роль 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/isissue/1890
Brent Washburne

1

Це старе запитання, але ви також можете використовувати пакет експрес-валідатора для перевірки параметрів запитів

експрес-валідатор, версія 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);
        });

    });

});

1

Завжди використовуйте mongoose.Types.ObjectId('your id')для умов вашого запиту, це перевірить поле id перед тим, як запустити ваш запит, у результаті ваша програма не вийде з ладу.



0

Те, як я вирішую цю проблему, перетворює ідентифікатор у рядок

мені подобається це з 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

Я натрапив на цю проблему при спробі видалити елемент за допомогою мангуста і отримав ту саму помилку. Переглянувши рядок, що повертається, я виявив, що всередині повернутої рядки є додаткові пробіли, що спричинило помилку для мене. Отже, я застосував кілька відповідей, наданих тут, щоб виявити помилковий ідентифікатор, а потім видалити зайві пробіли з рядка. Ось код, який працював на мене, щоб остаточно вирішити проблему.

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" як ідентифікатор
Wyrone

0

У мене були проблеми з цим і вирішили робити mongoose.ObjectId(id)без цьогоTypes

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.