¿Cuál es el error de Mongoose? ¿Falló la conversión a ObjectId para el valor XXX en la ruta "_id"?

122

Al enviar una solicitud a /customers/41224d776a326fb40f000001y un documento con _id 41224d776a326fb40f000001no existe, doces nully estoy devolviendo un 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);
    });
  };

Sin embargo, cuando _idno coincide con lo que Mongoose espera como "formato" (supongo), por ejemplo, GET /customers/foose devuelve un error extraño:

CastError: Error de conversión a ObjectId para el valor "foo" en la ruta "_id".

Entonces, ¿qué es este error?

gremo
fuente

Respuestas:

182

El findByIdmétodo de Mongoose envía el idparámetro al tipo de _idcampo del modelo para que pueda consultar correctamente el documento correspondiente. Este es un ObjectId pero "foo"no es un ObjectId válido, por lo que la conversión falla.

Esto no sucede 41224d776a326fb40f000001porque esa cadena es un ObjectId válido.

Una forma de resolver esto es agregar una verificación antes de su findByIdllamada para ver si ides un ObjectId válido o no así:

if (id.match(/^[0-9a-fA-F]{24}$/)) {
  // Yes, it's a valid ObjectId, proceed with `findById` call.
}
JohnnyHK
fuente
4
@Gremo Solo puede elegir un tipo para usar _iden su esquema de Mongoose. En el "bla"caso de que use un tipo de en Stringlugar del predeterminado ObjectIdy no necesitaría agregar esta verificación, ya que cualquier cosa se puede convertir en una cadena.
JohnnyHK
2
Entiendo, pero me gustaría evitar este cheque. ¿Cómo puedo crear una nueva a ObjectIdpartir de una cadena determinada (de la GETsolicitud) para pasarla al findByIdmétodo?
Gremo
@Gremo No puedes. Solo puede construir ObjectIds a partir de 24 cadenas de caracteres hexadecimales.
JohnnyHK
1
Puede usar find ({_ id: yourId}, ...) para consultar el documento con esa identificación (única). Eso, y la respuesta de JohnnyHK para agregar _id a su esquema (con el tipo de 'cadena' deseado) es la solución completa a su problema.
Steve Hollasch
1
En estos días, también se pueden convertir 12 cadenas de caracteres en un ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Dan Ross
50

Utilice funciones existentes para comprobar ObjectID.

var mongoose = require('mongoose');
mongoose.Types.ObjectId.isValid('your id here');
xpepermint
fuente
15
Tenga cuidado al usar ese método, ya que tiene el curioso comportamiento de tratar cualquier cadena de 12 bytes como válida. Entonces, incluso devuelve verdadero para su 'your id here'ejemplo. github.com/mongodb/js-bson/issues/106
JohnnyHK
console.log ("aquí"); let i = new mongoose.Types.ObjectId (userId.id); console.log ("ahora aquí"); // esta consola ni siquiera imprime
yogesh agrawal
11

¿Estás analizando esa cadena como ObjectId?

Aquí en mi aplicación, lo que hago es:

ObjectId.fromString( myObjectIdString );
gustavohenke
fuente
Sí, debería hacerlo, porque está consultando un tipo de ObjectId, por lo que se necesita la conversión.
gustavohenke
1
Prueba mongoose.Types.ObjectId.
gustavohenke
1
Funciona, pero obtengo "ObjectId no válido" al pasar "foo". Entonces, ¿cuál es el punto de crear un ObjectId a partir de una cadena, si puede fallar?
gremo
Según los documentos de MongoDB, los ObjectIds deben tener solo 24 bytes hexadecimales.
gustavohenke
1
fromStringno es una función
WasiF
8

Tengo el mismo problema, agrego
_id: String .in esquema y luego comienza a funcionar

s.babar
fuente
un año después, esto me salvó cuando lo
usé
Gracias, te quedaste atascado en un pequeño punto después de trabajar durante 15 horas seguidas.
Black Mamba
8

Tuve que mover mis rutas por encima de otras rutas que están capturando los parámetros de la ruta:

// 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);
Ryan Dhungel
fuente
Eso fue todo. Ojalá encontrara tu respuesta hace una hora. ¡Salud!
Sodbileg Gansukh
Esto funcionó para mí. Tengo curiosidad por conocer la razón detrás de este error. ¿Podría explicar cómo el hecho de mover la ruta por debajo de las rutas regulares hizo que el error desapareciera?
Vishwak
Esto también me funcionó. Parece que / test / create satisface esto / test /: id con id = create. y la cadena no se puede convertir a_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"});
        }

lo mejor es verificar la validez

yogesh agrawal
fuente
3

En mi caso, tuve que agregar _id: Objecta mi esquema, y ​​luego todo funcionó bien.

Crowdpleasr
fuente
2

También puede usar ObjectId.isValid como el siguiente:

if (!ObjectId.isValid(userId)) return Error({ status: 422 })
ZEE
fuente
1
ReferenceError: ObjectId no está definido
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
}
Brajalal Pal
fuente
Hay otras respuestas que proporcionan la pregunta del OP y se publicaron hace muchos años. Cuando publique una respuesta, asegúrese de agregar una nueva solución o una explicación sustancialmente mejor, especialmente cuando responda preguntas anteriores. Las respuestas de solo código se consideran de baja calidad: asegúrese de proporcionar una explicación de lo que hace su código y cómo resuelve el problema.
help-info.de
2

Me enfrenté a algo similar recientemente y lo resolví detectando el error para averiguar si se trataba de un error de 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);
    }
});
Erons
fuente
1

Fui con una adaptación de la solución @gustavohenke, implementando cast ObjectId en un try-catch envuelto alrededor del código original para aprovechar el error de conversión de ObjectId como método de validación.

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);
  }
};
Charney Kaye
fuente
1
Esto habría sido bueno de usar, pero fromString () ya no existe: github.com/Automattic/mongoose/issues/1890
Brent Washburne
1

Esta es una pregunta antigua, pero también puede usar el paquete express-validator para verificar los parámetros de solicitud

express-validator versión 4 (más reciente):

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 versió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);
        });

    });

});
YouneL
fuente
1

Utilice siempre mongoose.Types.ObjectId('your id')para las condiciones en su consulta, validará el campo de identificación antes de ejecutar su consulta, como resultado, su aplicación no se bloqueará.

Suman
fuente
0

La forma en que soluciono este problema es transformando la identificación en una cadena

me gusta elegante con comillas invertidas: `${id}`

esto debería solucionar el problema sin gastos generales

AiU
fuente
0

ObjectId se compone de las siguientes cosas.

  1. un valor de 4 bytes que representa los segundos desde la época de Unix
  2. un valor aleatorio de 5 bytes (ID de máquina 3 bytes e ID de procesador 2 bytes)
  3. un contador de 3 bytes, comenzando con un valor aleatorio.

La forma correcta de validar si el objectId es válido es mediante el uso del método estático de la propia clase ObjectId.

mongoose.Types.ObjectId.isValid (sample_object_id)

Sushil Kadu
fuente
0

Convertir cadena en 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
WasiF
fuente
0

Detección y corrección del error ObjectID

Me encontré con este problema al intentar eliminar un elemento con mangosta y obtuve el mismo error. Después de mirar la cadena de retorno, encontré que había algunos espacios adicionales dentro de la cadena devuelta que me causaron el error. Entonces, apliqué algunas de las respuestas proporcionadas aquí para detectar la identificación errónea y luego eliminé los espacios adicionales de la cadena. Aquí está el código que me funcionó para finalmente resolver el problema.

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

Esto funcionó para mí y supongo que si otros elementos comienzan a aparecer en la cadena de devolución, se pueden eliminar de manera similar.

Espero que esto ayude.

Jim Bray
fuente
0

Solucioné este problema cambiando el orden de las rutas.

idionisio
fuente
Esto no parece ser una respuesta. En el mejor de los casos, es un comentario.
MS
Esto funcionó para mí, tenía 2 rutas para blogs: '/ blogs / create' y 'blogs /: id'. Y este último fue el primero en el orden de las rutas. Entonces, cuando fui a '/ blogs / create' mangosta, tomé 'create' como identificación
Wyrone
0

Estaba teniendo problemas con esto y lo arreglé mongoose.ObjectId(id)sinTypes

Juany
fuente