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.