ERROR: ValidationError: CastError: Cast to ObjectI

2019-09-14 18:38发布

问题:

SITUATION:

It seems I must have made a mistake in my Mongoose Model or in one of the parameters that are passed to the route.

I am fairly new to the angular2 architecture, so the mistake might be quite obvious.

ERROR:

  ERROR: ValidationError: CastError: Cast to ObjectID failed for value "{ title: 'das',
      username: 'John',
      choice1: 'FSDAFASDF',
      choice2: 'FDSAFD',
      counter1: 11,
      counter2: 0,
      pollId: '5920598ade7567001170c810',
      userId: '591c15b3ebbd170aa07cd476' }" at path "poll"

CODE:

route

router.patch('/', function (req, res, next) {
    var decoded = jwt.decode(req.query.token);
    User.findById(decoded.user._id, function (err, user) {
      user.votes = req.body.votes;
      user.save(function(err, result) {
          if (err) {
              console.log("ERROR: "+err);
              return res.status(500).json({
                  title: 'An error occurred',
                  error: err
              });
          }
          res.status(201).json({
              poll: 'Vote Saved',
              obj: result
          });
      });
   });
});

models/user:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongooseUniqueValidator = require('mongoose-unique-validator');

var schema = new Schema({
    firstName: {type: String, required: true},
    lastName: {type: String, required: true},
    password: {type: String, required: true},
    email: {type: String, required: true, unique: true},
    polls: [{type: Schema.Types.ObjectId, ref: 'Poll'}],
    votes: [{
      poll: {type: Schema.Types.ObjectId, ref: 'Poll'},
      choice: {type: Number},
    }],
});

schema.plugin(mongooseUniqueValidator);

module.exports = mongoose.model('User', schema);

models/poll

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

var User = require('./user');

var schema = new Schema({
    title: {type: String, required: true},
    choice1: {type: String, required: true},
    choice2: {type: String, required: true},
    counter1: {type: Number, required: true},
    counter2: {type: Number, required: true},
    user: {type: Schema.Types.ObjectId, ref: 'User'}
});

schema.post('remove', function (poll) {
    User.findById(poll.user, function (err, user) {
        user.polls.pull(poll);
        user.save();
    });
});

module.exports = mongoose.model('Poll', schema);

EDIT:

router.patch('/', function (req, res, next) {
    var decoded = jwt.decode(req.query.token);
    console.log("VALID ID ? :"+mongoose.Types.ObjectId.isValid(decoded.user._id));
    console.log("DECODED USER ID:"+ decoded.user._id);
    User.findByIdAndUpdate(decoded.user._id, {votes: req.body.votes}, function (err, user) {
      user.save(function(err, result) {
          if (err) {
              console.log("ERROR: "+err);
              return res.status(500).json({
                  title: 'An error occurred',
                  error: err
              });
          }
          res.status(201).json({
              poll: 'Vote Saved',
              obj: result
          });
      });
   });
});

回答1:

I'm thoughtfully guessing that this particular piece of code is what causes the issue:

    ...
    User.findById(decoded.user._id, function (err, user) {
      user.votes = req.body.votes;
      user.save(function(err, result) {
    ...

mongoose is trying to resave the model and overwrite it's _id property with a plain string, whereas it should be an instance of the ObjectId.

Instead of using save to update your model, please try to use findByIdAndUpdate instead. If this is working, than my guess would be correct.

User.findByIdAndUpdate(decode.user._id, {votes: req.body.votes}, function (err, user) {

Or, cast the string _id into an ObjectId manually

    ...
    User.findById(decoded.user._id, function (err, user) {
      user.votes = req.body.votes;
      user._id = mongoose.Types.ObjectId(user._id);
      user.save(function(err, result) {
    ...

The first is preferred.