Co to jest błąd Mongoose Przesyłanie do ObjectId nie powiodło się dla wartości XXX w ścieżce „_id”?


122

Gdy wysyłam zapytanie do, /customers/41224d776a326fb40f000001a dokument z którym _id 41224d776a326fb40f000001nie ma, docto nulli zwracam 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);
    });
  };

Jeśli jednak _idnie odpowiada temu, czego oczekuje Mongoose jako „format” (przypuszczam), na przykład z GET /customers/foodziwnym błędem jest zwracany:

CastError: Przesyłanie do ObjectId nie powiodło się dla wartości „foo” w ścieżce „_id”.

Więc co to za błąd?

Odpowiedzi:


182

findByIdMetoda Mongoose rzutuje idparametr na typ pola modelu, _iddzięki czemu może on poprawnie wysyłać zapytania o pasujący dokument. To jest ObjectId, ale "foo"nie jest to prawidłowy ObjectId, więc rzutowanie kończy się niepowodzeniem.

Nie dzieje się tak w przypadku, 41224d776a326fb40f000001ponieważ ten ciąg jest prawidłowym ObjectId.

Jednym ze sposobów rozwiązania tego problemu jest dodanie sprawdzenia przed findByIdwywołaniem, aby sprawdzić, czy idjest to prawidłowy ObjectId, czy nie:

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

4
@Gremo Możesz wybrać tylko jeden typ do użycia _idw schemacie Mongoose. W "bla"przypadku, gdy użyjesz typu Stringzamiast domyślnego ObjectIdi nie będziesz musiał dodawać tego sprawdzenia, ponieważ wszystko może zostać rzutowane na łańcuch.
JohnnyHK,

2
Rozumiem, ale chciałbym uniknąć tej kontroli. Jak mogę utworzyć nowy ObjectIdz podanego ciągu (z GETżądania) w celu przekazania go do findByIdmetody?
gremo

@Gremo Nie możesz. Możesz konstruować ObjectIds tylko z 24 ciągów znaków szesnastkowych.
JohnnyHK,

1
Możesz po prostu użyć find ({_ id: yourId}, ...), aby wyszukać dokument z tym (unikalnym) identyfikatorem. To, i odpowiedź JohnnyHK na dodanie _id do twojego schematu (z pożądanym typem 'string') jest pełnym rozwiązaniem twojego problemu.
Steve Hollasch,

1
Obecnie 12 ciągów znaków można również rzutować na ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Dan Ross

50

Użyj istniejących funkcji do sprawdzenia ObjectID.

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

15
Ostrożnie używaj tej metody, ponieważ ma dziwne zachowanie traktowania dowolnego 12-bajtowego ciągu jako prawidłowego. Więc nawet zwraca prawdę dla twojego 'your id here'przykładu. github.com/mongodb/js-bson/issues/106
JohnnyHK

console.log ("tutaj"); let i = new mongoose.Types.ObjectId (userId.id); console.log ("teraz tutaj"); // ta konsola nawet nie drukuje
yogesh agrawal

11

Czy analizujesz ten ciąg jako ObjectId ?

Tutaj w mojej aplikacji robię:

ObjectId.fromString( myObjectIdString );

Tak, powinieneś, ponieważ odpytujesz o typ ObjectId, więc rzutowanie jest potrzebne.
gustavohenke

1
Spróbuj mongoose.Types.ObjectId.
gustavohenke

1
Działa, ale otrzymuję „Invalid ObjectId” podczas przekazywania „foo”. Więc jaki jest sens tworzenia ObjectId z łańcucha, jeśli może się nie powieść?
gremo

Zgodnie z dokumentacją MongoDB, ObjectIds muszą mieć tylko 24 bajty szesnastkowe.
gustavohenke

1
fromStringnie jest funkcją
WasiF

8

Mam ten sam problem, dodaję
_id: String .in schema, a następnie zaczynam pracę


rok później to uratowało mnie podczas korzystania z connect-mongo
Ren44

Dziękuję, że utknąłeś w małym punkcie po pracy przez 15 godzin bez przerwy.
Black Mamba

8

Musiałem przenieść moje trasy na inne trasy, które przechwytują parametry trasy:

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

To było to. Żałuję, że nie znalazłem Twojej odpowiedzi godzinę temu. Twoje zdrowie!
Sodbileg Gansukh

To zadziałało dla mnie. Ciekawi mnie powód tego błędu. Czy mógłbyś wyjaśnić, w jaki sposób przesunięcie trasy poniżej zwykłych tras spowodowało zniknięcie błędu?
Vishwak

To też działało. Wygląda na to, że / test / create spełnia to / test /: id z id = create. a string nie może być rzutowany na 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"});
        }

najlepiej sprawdzić ważność


3

W moim przypadku musiałem dodać _id: Objectdo mojego schematu, a potem wszystko działało dobrze.


2

Możesz również użyć ObjectId.isValid w następujący sposób:

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

1
ReferenceError: ObjectId nie jest zdefiniowany
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
}

Istnieją inne odpowiedzi, które zawierają pytanie PO, i zostały one opublikowane wiele lat temu. Pisząc odpowiedź, upewnij się, że dodałeś nowe rozwiązanie lub znacznie lepsze wyjaśnienie, szczególnie w przypadku odpowiedzi na starsze pytania. Odpowiedzi zawierające tylko kod są uważane za niskiej jakości: pamiętaj, aby wyjaśnić, co robi Twój kod i jak rozwiązuje problem.
help-info.de

2

Ostatnio miałem do czynienia z czymś podobnym i rozwiązałem to, wychwytując błąd, aby dowiedzieć się, czy jest to błąd 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

Poszedłem z adaptacją rozwiązania @gustavohenke, implementując rzutowanie ObjectId w try-catch owiniętym wokół oryginalnego kodu, aby wykorzystać niepowodzenie rzutowania ObjectId jako metody walidacji.

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
Byłoby fajnie w użyciu, ale fromString () już nie istnieje: github.com/Automattic/mongoose/issues/1890
Brent Washburne

1

To jest stare pytanie, ale możesz również użyć pakietu Express-Validator, aby sprawdzić parametry żądania

express-validator wersja 4 (najnowsza):

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

Zawsze używaj mongoose.Types.ObjectId('your id')warunków w zapytaniu, zweryfikuje pole id przed uruchomieniem zapytania, w wyniku czego aplikacja nie ulegnie awarii.



0

Sposób rozwiązania tego problemu polega na przekształceniu identyfikatora w ciąg

lubię to fantazyjne z backtick: `${id}`

powinno to rozwiązać problem bez narzutów


0

ObjectId składa się z następujących elementów.

  1. 4-bajtowa wartość reprezentująca sekundy od epoki Uniksa
  2. 5-bajtowa wartość losowa (identyfikator komputera 3 bajty i identyfikator procesora 2 bajty)
  3. licznik 3-bajtowy, rozpoczynający się od losowej wartości.

Prawidłowym sposobem sprawdzenia, czy objectId jest poprawny, jest użycie metody statycznej z samej klasy ObjectId.

mongoose.Types.ObjectId.isValid (sample_object_id)


0

Rzutuj ciąg na 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

Wykrywanie i naprawianie błędu ObjectID

Natknąłem się na ten problem, próbując usunąć element za pomocą mangusty i otrzymałem ten sam błąd. Po przejrzeniu zwracanego ciągu stwierdziłem, że wewnątrz zwracanego ciągu znajdują się dodatkowe spacje, które spowodowały błąd. Tak więc zastosowałem kilka z podanych tutaj odpowiedzi, aby wykryć błędny identyfikator, a następnie usunąłem dodatkowe spacje z ciągu. Oto kod, który zadziałał, aby ostatecznie rozwiązać problem.

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

U mnie to zadziałało i zakładam, że jeśli inne elementy zaczną pojawiać się w ciągu zwrotnym, można je usunąć w podobny sposób.

Mam nadzieję, że to pomoże.


0

Naprawiłem ten problem zmieniając kolejność tras.


To nie wydaje się być odpowiedzią. W najlepszym przypadku jest to komentarz.
MS

To zadziałało dla mnie, miałem 2 trasy dla blogów: „/ blogs / create” i „blogs /: id”. A ten ostatni zajął pierwsze miejsce w kolejności tras. Więc kiedy poszedłem do '/ blogs / create', mongoose wziął 'create' jako identyfikator
Wyrone

0

Miałem z tym problemy i naprawiłem mongoose.ObjectId(id)bezTypes

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.