Apa kesalahan Mongoose yang gagal dalam Cast to ObjectId untuk nilai XXX di jalur "_id"?


122

Saat mengirim permintaan ke /customers/41224d776a326fb40f000001dan dokumen dengan _id 41224d776a326fb40f000001tidak ada, docadalah nulldan saya mengembalikan 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);
    });
  };

Namun, ketika _idtidak cocok dengan apa yang diharapkan Mongoose sebagai "format" (saya kira) misalnya dengan GET /customers/fookesalahan aneh dikembalikan:

CastError: Transmisi ke ObjectId gagal untuk nilai "foo" di jalur "_id".

Jadi apa kesalahan ini?

Jawaban:


182

findByIdMetode Mongoose mentransmisikan idparameter ke jenis bidang model _idsehingga dapat meminta dokumen yang cocok dengan benar. Ini adalah ObjectId tetapi "foo"bukan ObjectId yang valid sehingga transmisi gagal.

Ini tidak terjadi 41224d776a326fb40f000001karena string itu adalah ObjectId yang valid.

Salah satu cara untuk mengatasinya adalah dengan menambahkan tanda centang sebelum findByIdpanggilan Anda untuk melihat apakah idObjectId valid atau tidak seperti itu:

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

4
@Gremo Anda hanya dapat memilih satu jenis untuk digunakan _iddalam skema Mongoose Anda. Dalam "bla"kasus ini Anda akan menggunakan jenis Stringalih - alih default ObjectIddan Anda tidak perlu menambahkan centang ini karena apa pun dapat dilemparkan ke string.
JohnnyHK

2
Saya mengerti, tapi saya ingin menghindari pemeriksaan ini. Bagaimana cara membuat yang baru ObjectIddari string yang diberikan (dari GETpermintaan) untuk meneruskannya ke findByIdmetode?
gremo

@Go Anda tidak bisa. Anda hanya dapat membuat ObjectIds dari 24 string karakter hex.
JohnnyHK

1
Anda cukup menggunakan find ({_ id: yourId}, ...) untuk membuat kueri dokumen dengan id (unik) itu. Itu, dan jawaban JohnnyHK untuk menambahkan _id ke skema Anda (dengan jenis 'string' yang Anda inginkan) adalah solusi lengkap untuk masalah Anda.
Steve Hollasch

1
Saat ini, 12 string karakter juga dapat dilemparkan ke ObjectId. ObjectId("000000000000") --> 303030303030303030303030
Dan Ross

50

Gunakan fungsi yang ada untuk memeriksa ObjectID.

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

15
Berhati-hatilah saat menggunakan metode tersebut karena memiliki perilaku aneh dalam memperlakukan string 12-byte sebagai valid. Jadi bahkan mengembalikan true untuk 'your id here'contoh Anda . github.com/mongodb/js-bson/issues/106
JohnnyHK

console.log ("di sini"); biarkan i = new mongoose.Types.ObjectId (userId.id); console.log ("sekarang di sini"); // konsol ini bahkan tidak mencetak
yogesh agrawal

11

Apakah Anda mengurai string itu sebagai ObjectId?

Di sini, di aplikasi saya, yang saya lakukan adalah:

ObjectId.fromString( myObjectIdString );

Ya, Anda harus, karena Anda menanyakan tipe ObjectId, jadi cast diperlukan.
gustavohenke

1
Coba mongoose.Types.ObjectId.
gustavohenke

1
Berfungsi, tapi saya mendapatkan "ObjectId tidak valid" saat meneruskan "foo". Jadi apa gunanya membuat ObjectId dari string, jika mungkin gagal?
gremo

Sesuai dokumen MongoDB, ObjectIds harus terdiri dari 24 byte heksadesimal saja.
gustavohenke

1
fromStringbukan fungsi
WasiF

8

Saya memiliki masalah yang sama saya menambahkan
_id: String .in skema kemudian mulai bekerja


setahun kemudian ini menyelamatkan saya saat menggunakan dengan connect-mongo
Ren44

Terima kasih, Anda terjebak pada masalah kecil setelah bekerja selama 15 jam berturut-turut.
Black Mamba

8

Saya harus memindahkan rute saya di atas rute lain yang menangkap parameter rute:

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

Itu dia. Saya berharap saya menemukan jawaban Anda satu jam yang lalu. Bersulang!
Sodbileg Gansukh

Ini berhasil untuk saya. Saya penasaran dengan alasan di balik kesalahan ini. Bisakah Anda menjelaskan bagaimana memindahkan rute di bawah rute biasa menyebabkan kesalahan hilang?
Vishwak

Ini berhasil juga bagi saya. Sepertinya The / test / create memenuhi ini / test /: id dengan id = create. dan string tidak dapat diubah menjadi to_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"});
        }

yang terbaik adalah memeriksa validitas


3

Dalam kasus saya, saya harus menambahkan _id: Objectke Skema saya, dan kemudian semuanya bekerja dengan baik.


2

Anda juga dapat menggunakan ObjectId.isValid seperti berikut:

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

1
ReferenceError: ObjectId tidak ditentukan
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
}

Ada jawaban lain yang memberikan pertanyaan OP, dan jawaban itu diposting beberapa tahun yang lalu. Saat memposting jawaban, pastikan Anda menambahkan solusi baru, atau penjelasan yang jauh lebih baik, terutama saat menjawab pertanyaan lama. Jawaban hanya-kode dianggap berkualitas rendah: pastikan untuk memberikan penjelasan tentang fungsi kode Anda dan bagaimana cara menyelesaikan masalah.
help-info.de

2

Saya dihadapkan dengan sesuatu yang serupa baru-baru ini dan menyelesaikannya dengan menangkap kesalahan untuk mengetahui apakah itu kesalahan 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

Saya menggunakan adaptasi dari solusi @gustavohenke, mengimplementasikan ObjectId cor dalam percobaan-menangkap yang dibungkus di sekitar kode asli untuk memanfaatkan kegagalan casting ObjectId sebagai metode validasi.

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
Ini akan menyenangkan untuk digunakan, tetapi fromString () tidak ada lagi: github.com/Automattic/mongoose/issues/1890
Brent Washburne

1

Ini adalah pertanyaan lama tetapi Anda juga dapat menggunakan paket validator-ekspres untuk memeriksa parameter permintaan

express-validator versi 4 (terbaru):

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

Selalu gunakan mongoose.Types.ObjectId('your id')untuk kondisi dalam kueri Anda, ini akan memvalidasi bidang id sebelum menjalankan kueri Anda sebagai hasilnya aplikasi Anda tidak akan mogok.



0

Cara saya memperbaiki masalah ini adalah mengubah id menjadi string

Saya suka dengan backtick: `${id}`

ini seharusnya memperbaiki masalah tanpa biaya tambahan


0

ObjectId terdiri dari hal-hal berikut.

  1. nilai 4-byte yang mewakili detik sejak zaman Unix
  2. nilai acak 5-byte (ID Mesin 3 byte dan ID Prosesor 2 byte)
  3. penghitung 3-byte, dimulai dengan nilai acak.

Cara yang benar untuk memvalidasi jika objectId valid adalah dengan menggunakan metode statis dari kelas ObjectId itu sendiri.

mongoose.Types.ObjectId.isValid (sample_object_id)


0

Transmisikan string ke 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

Mendeteksi dan Mengoreksi Kesalahan ObjectID

Saya tersandung masalah ini ketika mencoba menghapus item menggunakan luwak dan mendapatkan kesalahan yang sama. Setelah melihat-lihat string kembali, saya menemukan ada beberapa spasi ekstra di dalam string yang dikembalikan yang menyebabkan kesalahan bagi saya. Jadi, saya menerapkan beberapa jawaban yang disediakan di sini untuk mendeteksi id yang salah lalu menghapus spasi ekstra dari string. Berikut adalah kode yang berhasil bagi saya untuk akhirnya menyelesaikan masalah tersebut.

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

Ini berhasil untuk saya dan saya berasumsi jika item lain mulai muncul di string kembali, mereka dapat dihapus dengan cara yang sama.

Saya harap ini membantu.


0

Saya memperbaiki masalah ini dengan mengubah urutan rute.


Ini sepertinya bukan jawaban. Paling banter, itu hanya komentar.
MS

Ini berhasil untuk saya, saya memiliki 2 rute untuk blog: '/ blog / create' dan 'blog /: id'. Dan yang terakhir datang lebih dulu dalam urutan rute. Jadi ketika saya pergi ke '/ blog / create' luwak mengambil 'buat' sebagai id
Wyrone

0

Saya mengalami masalah dengan ini dan tetap melakukannya mongoose.ObjectId(id)tanpaTypes

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.