Home > Mobile >  CastError: Cast to ObjectId failed for value "n" (type number) at path "propertyArray
CastError: Cast to ObjectId failed for value "n" (type number) at path "propertyArray

Time:07-18

I know there are a lot of similar problems on stackoverflow. Thing is, I can't solve it even following exactly mongodb documentation:

source

{
  _id: 4,
  grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 85, mean: 85, std: 8 }
  ]
}


db.students.updateOne(
   { _id: 4, "grades.grade": 85 },
   { $set: { "grades.$.std" : 6 } }
)

{
   "_id" : 4,
   "grades" : [
      { "grade" : 80, "mean" : 75, "std" : 8 },
      { "grade" : 85, "mean" : 90, "std" : 6 },
      { "grade" : 85, "mean" : 85, "std" : 8 }
   ]
}

Here's what I am trying with different combinations:

const { id, rateValue } = req.body


Book.updateOne({ _id: id, "userbookrates.user":ObjectId("62d1fbfa5a0a6281de43b528") }, {$set:{"userbookrates.$.rate": rateValue}})
    .then(r => {
        console.log(r, 'result log----')
    })
    .catch(e=> console.log(e))

My models:

BOOKS

const bookSchema = new Schema (
    {
    title: {
        type:String,
        required: [true, 'Mongoose - name is required']
    },
    author: {
        type:String,
        required: [true, 'Mongoose - author is required']
    },
    plot: {
        type:String,
        required: [true, 'Mongoose - plot is required']
    },
    genre: {
        type:String,
        required: [true, 'Mongoose - genre is required']
    },
    image: {
        type: String,
        default: 'catty'
    },
    owner: {
        type: Schema.Types.ObjectId, ref: 'User'
    },
    userbookrates: [{
        type: Schema.Types.ObjectId, ref: 'Bookrate'
    }],
    usersaved: [{
        type: Schema.Types.ObjectId, ref: 'User'
    }]
},
    {
      timestamps: true
    }
);

  module.exports = model('Book', bookSchema);

USER:

const userSchema = new Schema ({
    email: {
        type:String,
        required: true,
        required: [true, 'Mongoose - Email is required'],
        unique: true,
        match: [/^\w ([\.-]?\w )*@\w ([\.-]?\w )*(\.\w{2,3}) $/, 'Please fill a valid email address']
    },
    password: {
          type:String,
          required: [true, 'Mongoose - Password is required'],
    },
    username: {
          type: String
    },
    image: {
      type: String,
      default:'panda.png'
    },
    books: [{
          type: Schema.Types.ObjectId, ref: 'Book'
    }],
    bookrate: [{
          type: Schema.Types.ObjectId, ref: 'Bookrate'
    }],
    booksaved: [{
      type: Schema.Types.ObjectId, ref: 'Book'
    }],
    followers: [{
      type: Schema.Types.ObjectId, ref: 'User'
    }],
    following: [{
      type: Schema.Types.ObjectId, ref: 'User'
    }],
},
    {
      timestamps: true
    }
);

BOOKRATE:

const bookrateSchema = new Schema ({
    user: {
          type: Schema.Types.ObjectId, ref: 'User'
    },
    rate: {
        type: Number,
        required: [true, 'Mongoose - Rate is a MUST'],
    },
    // book: {
    //     type: Schema.Types.ObjectId, ref: 'Book'
    // }
},
    {
      timestamps: true
    }
);

As you can see, I referenced for leave reviews in each book from user account.

I would like users to be able to leave reviews to their profile books, so if one user leaves one, and needs to change it, I want to update it from this book (unique ID), inside an array of raviews/ratings just the single value of rate

userbookrates: [{
            type: Schema.Types.ObjectId, ref: 'Bookrate'
        }],

Some example of book:

{
  _id: new ObjectId("62d1fbd46dca32eab6e2f280"),
  title: 'The Leisure Seeker',
  author: 'Paolo Virzì',
  plot: 'A runaway couple goes on an unforgettable journey in the faithful old RV they call The Leisure Seeker, traveling from Boston to The Ernest Hemingway Home in Key West. They recapture their passion for life and their love for each other on a road trip that provides revelation and surprise right up to the very end.',
  genre: 'drama',
  image: 'https://image.jpg',
  userbookrates: [
    {
      _id: new ObjectId("62d218c7c93acc30d3075f79"),
      user: new ObjectId("62d1fbfa5a0a6281de43b528"),
      rate: 5,
      createdAt: 2022-07-16T01:47:51.874Z,
      updatedAt: 2022-07-16T01:47:51.874Z,
      __v: 0
    },
    {
      _id: new ObjectId("62d2209796fd7924d5ea7279"),
      user: new ObjectId("62d1fbfa5a0a6281de43b528"),
      rate: 5,
      createdAt: 2022-07-16T02:21:11.566Z,
      updatedAt: 2022-07-16T02:21:11.566Z,
      __v: 0
    }
  ],
  usersaved: [],
  createdAt: 2022-07-15T23:44:20.100Z,
  updatedAt: 2022-07-16T02:21:11.581Z,
  __v: 0
} 

The ERROR:

**CastError: Cast to ObjectId failed for value "3" (type number) at path "userbookrates.$"**
    at model.Query.exec (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/query.js:4650:21)
    at model.Query.Query.then (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/query.js:4749:15)
    at /home/titoih/Code/api-opinoos/routes/user/user.routes.js:29:10
    at Layer.handle [as handle_request] (/home/titoih/Code/api-opinoos/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/titoih/Code/api-opinoos/node_modules/express/lib/router/route.js:137:13)
    at module.exports.checkAuth (/home/titoih/Code/api-opinoos/mid/mid.secure.js:4:9)
    at Layer.handle [as handle_request] (/home/titoih/Code/api-opinoos/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/titoih/Code/api-opinoos/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/home/titoih/Code/api-opinoos/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/home/titoih/Code/api-opinoos/node_modules/express/lib/router/layer.js:95:5) {
  messageFormat: undefined,
  stringValue: '"3"',
  kind: 'ObjectId',
  value: 3,
  path: 'userbookrates.$',
  **reason: BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters**
      at new BSONTypeError (/home/titoih/Code/api-opinoos/node_modules/bson/lib/error.js:41:28)
      at new ObjectId (/home/titoih/Code/api-opinoos/node_modules/bson/lib/objectid.js:65:23)
      at castObjectId (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/cast/objectid.js:24:12)
      at ObjectId.cast (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/schema/objectid.js:247:12)
      at ObjectId.SchemaType.applySetters (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/schematype.js:1179:12)
      at ObjectId.SchemaType._castForQuery (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/schematype.js:1613:15)
      at ObjectId.SchemaType.castForQuery (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/schematype.js:1603:15)
      at ObjectId.SchemaType.castForQueryWrapper (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/schematype.js:1580:20)
      at castUpdateVal (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/helpers/query/castUpdate.js:527:19)
      at walkUpdatePath (/home/titoih/Code/api-opinoos/node_modules/mongoose/lib/helpers/query/castUpdate.js:344:24),
  valueType: 'number'
}

Thank you.

CodePudding user response:

Try to retrieve the Book first and then use the $in operator to search only Bookrates with the specific ids:
(I used await so make sure to declare your parent function async)

const { id, rateValue } = req.body;

const book = await Book.findById(id);
if (!book) return;

await Bookrate.update(
  {
    _id: { $in: book.userbookrates },
    user: ObjectId('62d1fbfa5a0a6281de43b528'),
  },
  { rate: rateValue }
);
  • Related