Qual è l'errore di Mongoose trasmesso a ObjectId non riuscito per il valore XXX nel percorso "_id"?


122

Quando si invia una richiesta a /customers/41224d776a326fb40f000001e un documento con _id 41224d776a326fb40f000001non esiste, docè nulle sto restituendo 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);
    });
  };

Tuttavia, quando _idnon corrisponde a ciò che Mongoose si aspetta come "formato" (suppongo), ad esempio con GET /customers/foouno strano errore viene restituito:

CastError: Cast a ObjectId non riuscito per il valore "foo" nel percorso "_id".

Allora qual è questo errore?

Risposte:


182

Il findByIdmetodo di Mongoose esegue il cast del idparametro sul tipo di _idcampo del modello in modo che possa eseguire correttamente una query per il documento corrispondente. Questo è un ObjectId ma "foo"non è un ObjectId valido, quindi il cast non riesce.

Ciò non accade 41224d776a326fb40f000001perché quella stringa è un ObjectId valido.

Un modo per risolvere questo problema è aggiungere un controllo prima della findByIdchiamata per vedere se idè un ObjectId valido o meno:

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

4
@Gremo Puoi scegliere solo un tipo da utilizzare _idnel tuo schema Mongoose. Nel "bla"caso in cui utilizzeresti un tipo di Stringinvece del predefinito ObjectIde non avresti bisogno di aggiungere questo controllo poiché qualsiasi cosa può essere lanciata su una stringa.
JohnnyHK

2
Capisco, ma vorrei evitare questo controllo. Come posso crearne uno nuovo ObjectIdda una data stringa (dalla GETrichiesta) per passarlo al findByIdmetodo?
gremo

@Gremo Non puoi. È possibile costruire solo ObjectIds da 24 stringhe di caratteri esadecimali.
JohnnyHK

1
Puoi semplicemente usare find ({_ id: yourId}, ...) per cercare il documento con quell'ID (univoco). Questo e la risposta di JohnnyHK per aggiungere _id al tuo schema (con il tipo di "stringa" desiderato) è la soluzione completa al tuo problema.
Steve Hollasch

1
In questi giorni, è anche possibile eseguire il cast di 12 stringhe di caratteri a un ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Dan Ross

50

Usa le funzioni esistenti per controllare ObjectID.

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

15
Attento a usare questo metodo in quanto ha il curioso comportamento di considerare valida qualsiasi stringa di 12 byte. Quindi restituisce vero anche per il tuo 'your id here'esempio. github.com/mongodb/js-bson/issues/106
JohnnyHK

console.log ( "qui"); let i = new mongoose.Types.ObjectId (userId.id); console.log ("ora qui"); // questa console non stampa nemmeno
yogesh agrawal

11

Stai analizzando quella stringa come ObjectId?

Qui nella mia domanda, quello che faccio è:

ObjectId.fromString( myObjectIdString );

Sì, dovresti, perché stai interrogando un tipo ObjectId, quindi è necessario il cast.
gustavohenke

1
Prova mongoose.Types.ObjectId.
gustavohenke

1
Funziona, ma ricevo "Invalid ObjectId" quando passo "foo". Allora qual è il punto di creare un ObjectId da una stringa, se può fallire?
gremo

Secondo la documentazione di MongoDB, gli ObjectIds devono contenere solo 24 byte esadecimali.
gustavohenke

1
fromStringnon è una funzione
WasiF

8

Ho lo stesso problema che aggiungo
_id: String. Nello schema, quindi inizia a funzionare


un anno dopo questo mi ha salvato durante l'utilizzo con connect-mongo
Ren44

Grazie sei rimasto bloccato in un piccolo punto dopo aver lavorato per 15 ore di fila.
Black Mamba

8

Ho dovuto spostare i miei percorsi sopra altri percorsi che stanno catturando i parametri del percorso:

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

Questo è stato. Vorrei aver trovato la tua risposta un'ora fa. Saluti!
Sodbileg Gansukh

Questo ha funzionato per me. Sono curioso del motivo alla base di questo errore. Potresti spiegare in che modo lo spostamento del percorso sotto i percorsi regolari ha causato la scomparsa dell'errore?
Vishwak

Questo ha funzionato anche per me. Sembra che / test / create soddisfi questo / test /: id con id = create. e la stringa non può essere trasmessa 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"});
        }

la cosa migliore è verificare la validità


3

Nel mio caso, ho dovuto aggiungere _id: Objectal mio schema e poi tutto ha funzionato bene.


2

Puoi anche utilizzare ObjectId.isValid come segue:

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

1
ReferenceError: ObjectId non è definito
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
}

Ci sono altre risposte che forniscono la domanda del PO e sono state pubblicate molti anni fa. Quando pubblichi una risposta, assicurati di aggiungere una nuova soluzione o una spiegazione sostanzialmente migliore, soprattutto quando rispondi a domande meno recenti. Le risposte di solo codice sono considerate di bassa qualità: assicurati di fornire una spiegazione su cosa fa il tuo codice e come risolve il problema.
help-info.de

2

Mi sono trovato di fronte a qualcosa di simile di recente e l'ho risolto rilevando l'errore per scoprire se si tratta di un errore di 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

Sono andato con un adattamento della soluzione @gustavohenke, implementando cast ObjectId in un try-catch avvolto attorno al codice originale per sfruttare il fallimento del casting ObjectId come metodo di convalida.

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
Sarebbe stato carino da usare, ma fromString () non esiste più: github.com/Automattic/mongoose/issues/1890
Brent Washburne

1

Questa è una vecchia domanda, ma puoi anche usare il pacchetto express-validator per controllare i parametri della richiesta

express-validator versione 4 (ultima):

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 versione 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

Usa sempre mongoose.Types.ObjectId('your id')per le condizioni nella tua query, convaliderà il campo id prima di eseguire la query, di conseguenza la tua app non andrà in crash.



0

Il modo in cui risolvo questo problema sta trasformando l'id in una stringa

mi piace fantasia con il backtick: `${id}`

questo dovrebbe risolvere il problema senza sovraccarico


0

ObjectId è composto dalle seguenti cose.

  1. un valore di 4 byte che rappresenta i secondi trascorsi dall'epoca Unix
  2. un valore casuale di 5 byte (ID macchina 3 byte e ID processore 2 byte)
  3. un contatore a 3 byte, che inizia con un valore casuale.

Il modo corretto per verificare se objectId è valido è utilizzare il metodo statico dalla stessa classe ObjectId.

mongoose.Types.ObjectId.isValid (sample_object_id)


0

Cast stringa a 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

Rilevamento e correzione dell'errore ObjectID

Mi sono imbattuto in questo problema durante il tentativo di eliminare un elemento utilizzando mangusta e ho ricevuto lo stesso errore. Dopo aver esaminato la stringa di ritorno, ho scoperto che c'erano degli spazi extra all'interno della stringa restituita che hanno causato l'errore per me. Quindi, ho applicato alcune delle risposte fornite qui per rilevare l'ID errato, quindi rimuovere gli spazi extra dalla stringa. Ecco il codice che ha funzionato per me per risolvere finalmente il 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("/");
      }
    });
});

Questo ha funzionato per me e presumo che se altri elementi iniziano ad apparire nella stringa di ritorno, possono essere rimossi in modo simile.

Spero che aiuti.


0

Ho risolto questo problema modificando l'ordine dei percorsi.


Questa non sembra essere una risposta. Nella migliore delle ipotesi, è un commento.
MS

Questo ha funzionato per me, avevo 2 percorsi per i blog: "/ blogs / create" e "blogs /: id". E quest'ultimo è arrivato primo nell'ordine dei percorsi. Quindi, quando sono andato a "/ blogs / create", mangusta ho preso "crea" come ID
Wyrone

0

Ho avuto problemi con questo e fissato fare mongoose.ObjectId(id)senzaTypes

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.