Что такое ошибка Mongoose. Ошибка преобразования в 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: сбой преобразования в ObjectId для значения «foo» в пути «_id».

Так что это за ошибка?

Ответы:


182

findByIdМетод Mongoose приводит 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 в вашу схему (с желаемым типом «строка») - полное решение вашей проблемы.
Стив Холлаш 03

1
В наши дни 12 символьных строк также можно преобразовать в ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Дэн Росс,

50

Используйте существующие функции для проверки ObjectID.

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

15
Будьте осторожны при использовании этого метода, так как он имеет любопытное поведение: любая 12-байтовая строка считается допустимой. Так что он даже возвращает true для вашего 'your id here'примера. github.com/mongodb/js-bson/issues/106
JohnnyHK

console.log ( "здесь"); пусть я = новый mongoose.Types.ObjectId (userId.id); console.log («теперь здесь»); // эта консоль даже не печатает
yogesh agrawal

11

Вы разбираете эту строку как ObjectId?

В моем приложении я делаю следующее:

ObjectId.fromString( myObjectIdString );

Да, вы должны, потому что вы запрашиваете тип ObjectId, поэтому требуется приведение.
gustavohenke

1
Попробуй mongoose.Types.ObjectId.
gustavohenke

1
Работает, но я получаю «Invalid ObjectId» при передаче «foo». Итак, какой смысл создавать ObjectId из строки, если это может привести к сбою?
gremo

Согласно документации MongoDB, ObjectIds должны быть только 24 шестнадцатеричными байтами.
gustavohenke

1
fromStringне функция
WasiF

8

У меня такая же проблема, как я добавляю
_id: String. В схеме, затем она начинает работать


год спустя это спасло меня при использовании с 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
}

Есть и другие ответы, которые задают вопрос OP, и они были опубликованы много лет назад. Публикуя ответ, убедитесь, что вы добавили либо новое решение, либо существенно лучшее объяснение, особенно при ответах на старые вопросы. Ответы, состоящие только из кода, считаются низкокачественными: обязательно объясните, что делает ваш код и как он решает проблему.
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 в 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);
  }
};

1
Было бы неплохо использовать это, но fromString () больше не существует: github.com/Automattic/mongoose/issues/1890
Брент Уошберн,

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

Способ, которым я исправляю эту проблему, - это преобразование идентификатора в строку

мне нравится фантазия с обратной кавычкой: `${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» в качестве идентификатора
Вайрон,

0

У меня были проблемы с этим, и я исправил работу mongoose.ObjectId(id)безTypes

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.