500 error: Cast to ObjectId failed for value at path \"_id\" for Mongoose model using ResourceJS

4.9k views Asked by At

Following step by step a simple installation of resourcejs as documented in this MEAN App repo, I get the following message, when I access the URL http://localhost:3000/movie/584c6f00cf996a9956784807:

{"status":500,"message":"Cast to ObjectId failed for value \"584dd2842a056e4a648751b5\" at path \"_id\" for model \"movie\"","errors":{}}

POST requests work too, but PUT and DELETE do not.

index.js

var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var methodOverride = require('method-override');
var _ = require('lodash');

var app = express();

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(methodOverride('X-HTTP-Method-Override'));

// CORS Support
app.use(function(req, res, next) { 
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

mongoose.connect('mongodb://localhost/meanapp');
mongoose.connection.once('open', function() {

  // Load the models.
  app.models = require('./models/index');

  var routes = require('./routes');
  var numberOfRoutes = 1;
  _.each(routes, function(controller, route) {
    app.use(route, controller(app, route));
  });

  app.listen(3000);
});

MovieController.js

var Resource = require('resourcejs');
module.exports = function(app, route) {

  // Setup the controller for REST;
  Resource(app, '', route, app.models.movie).rest();

  // Return middleware.
  return function(req, res, next) {
    next();
  };
};

The Movie model looks just like this, and is being served this way.

My point of interest is that ResourceJS has this following code, which seems to not be able to parse correctly an ID into a MongoDB ObjectID:

/**
 * Register the GET method for this resource.
 */
get: function(options) {
    (…)
    var search = {'_id': req.params[this.name + 'Id']}; 
    (…)
}

What could possibly be messing this up?

Stats Windows 10 — 64-bit OS, x64-based processor MongoDB v3.2.7, 64-bit NodeJS v4.4.7 Mongoose v4.7.6

1

There are 1 answers

6
num8er On BEST ANSWER

Because mongoose wants ObjectId but You're passing string as _id, so You should typecast it.

Try this:

var 
  mongoose = require('mongoose');
  ObjectId = mongoose.Schema.Types.ObjectId;

/**
 * Register the GET method for this resource.
 */
get: function(options) {
    (…)
    var param = req.param[this.name + 'Id'];
    var search = {'_id': new ObjectId(param)}; 
    (…)
}

If You need universal solution that works with any version of Mongoose and Mongo just define _id field as string and use uuid.v4 to generate unique values:

var uuid = require('uuid');
var mongoose = require('mongoose');

// Create the MovieSchema.
var MovieSchema = new mongoose.Schema({
    _id: { 
      type: String, 
      index: { unique: true }, 
      default: uuid.v4 
    },
    title: {
       type: String,
       required: true
    },
    url: {
      type: String,
      required: true
    }
 });

 // Export the model.
 module.exports = mongoose.model('movie', MovieSchema);

So in this case Your ResourceJS will stay as before and work properly:

get: function(options) {
    (…)
    var search = {'_id': req.param[this.name + 'Id']}; 
    (…)
}

P.S. don't forget to install uuid package:

npm i --save uuid