O que é erro do Mongoose Cast to ObjectId falhou para o valor XXX no caminho “_id”?


122

Ao enviar uma solicitação para /customers/41224d776a326fb40f000001e um documento com _id 41224d776a326fb40f000001não existe, docé nulle estou retornando um 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);
    });
  };

No entanto, quando _idnão corresponde ao que o Mongoose espera como "formato" (suponho), por exemplo, com GET /customers/fooum erro estranho é retornado:

CastError: a conversão para ObjectId falhou para o valor "foo" no caminho "_id".

Então, qual é esse erro?

Respostas:


182

O findByIdmétodo do Mongoose converte o idparâmetro para o tipo de _idcampo do modelo para que ele possa consultar corretamente o documento correspondente. Este é um ObjectId, mas "foo"não é um ObjectId válido, portanto, a conversão falha.

Isso não acontece 41224d776a326fb40f000001porque essa string é um ObjectId válido.

Uma maneira de resolver isso é adicionar uma verificação antes de sua findByIdchamada para ver se idé um ObjectId válido ou não:

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

4
@Gremo Você só pode escolher um tipo para usar _idem seu esquema Mongoose. No "bla"caso, você usaria um tipo de em Stringvez do padrão ObjectIde não precisaria adicionar essa verificação, pois qualquer coisa pode ser convertida em uma string.
— JohnnyHK

2
Eu entendo, mas gostaria de evitar essa verificação. Como posso criar um novo a ObjectIdpartir de uma determinada string (da GETsolicitação) para passá-lo para o findByIdmétodo?
— gremo

@Gremo Você não pode. Você só pode construir ObjectIds a partir de 24 cadeias de caracteres hexadecimais.
— JohnnyHK

1
Você pode apenas usar find ({_ id: yourId}, ...) para consultar o documento com aquele id (único). Isso e a resposta de JohnnyHK para adicionar _id ao seu esquema (com o tipo de 'string' desejado) é a solução completa para o seu problema.
— Steve Hollasch

1
Atualmente, 12 cadeias de caracteres também podem ser convertidas em um ObjectId. ObjectId("000000000000") --> 303030303030303030303030
— Dan Ross,

50

Use funções existentes para verificar ObjectID.

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

15
Cuidado ao usar esse método, pois ele tem o comportamento curioso de tratar qualquer string de 12 bytes como válida. Portanto, até retorna verdadeiro para o seu 'your id here'exemplo. github.com/mongodb/js-bson/issues/106
— JohnnyHK

console.log ("aqui"); let i = new mongoose.Types.ObjectId (userId.id); console.log ("agora aqui"); // este console nem mesmo imprime
— yogesh agrawal

11

Você está analisando essa string como ObjectId?

Aqui em meu aplicativo, o que eu faço é:

ObjectId.fromString( myObjectIdString );

Sim, deveria, porque você está consultando um tipo de ObjectId, então o elenco é necessário.
— gustavohenke

1
Experimente mongoose.Types.ObjectId.
— gustavohenke

1
Funciona, mas recebo "ObjectId inválido" ao passar "foo". Então, de que adianta criar um ObjectId a partir de uma string, se ele pode falhar?
— gremo

De acordo com os documentos do MongoDB, ObjectIds deve ter apenas 24 bytes hexadecimais.
— gustavohenke

1
fromStringnão é uma função
— WasiF

8

Eu tenho o mesmo problema, adiciono
_id: String .in schema e então ele começa a funcionar


um ano depois, isso me salvou ao usar com connect-mongo
— Ren44

Obrigado, você ficou preso em um pequeno ponto depois de trabalhar por 15 horas direto.
— Black Mamba,

8

Tive que mover minhas rotas em cima de outras rotas que estão pegando os parâmetros de rota:

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

Foi isso. Eu gostaria de ter encontrado sua resposta uma hora atrás. Felicidades!
— Sodbileg Gansukh

Isso funcionou para mim. Estou curioso para saber o motivo desse erro. Você poderia explicar como o deslocamento da rota abaixo das rotas normais fez com que o erro desaparecesse?
— Vishwak

Isso funcionou para mim também. Parece que / test / create satisfaz este / test /: id com id = create. e a string não pode ser convertida para_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"});
        }

melhor é verificar a validade


3

No meu caso, tive que adicionar _id: Objectem meu Schema, e então tudo funcionou bem.


2

Você também pode usar ObjectId.isValid como o seguinte:

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

1
ReferenceError: ObjectId não 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
}

Existem outras respostas que fornecem a pergunta do OP, e elas foram publicadas há muitos anos. Ao postar uma resposta, certifique-se de adicionar uma nova solução ou uma explicação substancialmente melhor, especialmente ao responder a perguntas mais antigas. Respostas somente de código são consideradas de baixa qualidade: certifique-se de fornecer uma explicação sobre o que seu código faz e como ele resolve o problema.
— help-info.de

2

Eu me deparei com algo semelhante recentemente e resolvi pegando o erro para descobrir se é um erro do 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

Fui com uma adaptação da solução @gustavohenke, implementando cast ObjectId em um try-catch enrolado no código original para alavancar a falha da conversão de ObjectId como um método de validação.

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
Isso teria sido bom de usar, mas fromString () não existe mais: github.com/Automattic/mongoose/issues/1890
— Brent Washburne

1

Esta é uma questão antiga, mas você também pode usar o pacote express-validator para verificar os parâmetros de solicitação

express-validator versão 4 (mais recente):

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 versão 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

Sempre use mongoose.Types.ObjectId('your id')para condições em sua consulta, ele validará o campo id antes de executar sua consulta, como resultado, seu aplicativo não travará.



0

A maneira de corrigir esse problema é transformar o id em uma string

eu gosto de fantasia com backtick: `${id}`

isso deve resolver o problema sem sobrecarga


0

ObjectId é composto das seguintes coisas.

  1. um valor de 4 bytes que representa os segundos desde a época do Unix
  2. um valor aleatório de 5 bytes (ID da máquina 3 bytes e ID do processador 2 bytes)
  3. um contador de 3 bytes, começando com um valor aleatório.

A maneira correta de validar se o objectId é válido é usando o método estático da própria classe ObjectId.

mongoose.Types.ObjectId.isValid (sample_object_id)


0

Cast string para 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

Detectando e corrigindo o erro ObjectID

Eu tropecei neste problema ao tentar excluir um item usando o mangusto e obtive o mesmo erro. Depois de examinar a string de retorno, descobri que havia alguns espaços extras dentro da string retornada que causaram o erro para mim. Portanto, apliquei algumas das respostas fornecidas aqui para detectar o id incorreto e remover os espaços extras da string. Aqui está o código que funcionou para que eu finalmente resolvesse o 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("/");
      }
    });
});

Isso funcionou para mim e suponho que se outros itens começarem a aparecer na string de retorno, eles podem ser removidos de maneira semelhante.

Eu espero que isso ajude.


0

Corrigi este problema mudando a ordem das rotas.


Isso não parece ser uma resposta. Na melhor das hipóteses, é um comentário.
— MS

Isso funcionou para mim, eu tinha 2 rotas para blogs: '/ blogs / create' e 'blogs /: id'. E este último veio primeiro na ordem das rotas. Então, quando eu fui para '/ blogs / criar', mangusto peguei 'criar' como um id
— Wyrone

0

Eu estava tendo problemas com isso e resolvi ficar mongoose.ObjectId(id)semTypes

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.