Home > Software engineering >  $divide is mongoose is giving "Cast to Number failed for value"
$divide is mongoose is giving "Cast to Number failed for value"

Time:12-30

Here i am trying to update the 'rating' field of my document by taking average of previously existing value of the rating field and newly sent rating value.

this is my rating field specification in the model

rating: {
      type: Number,
      min: 0,
      max: 5,
      required: true,
},

this is my request body and controller function

const { newRating, bookID, userName, comment } = req.body;

const updateRating = await Book.findByIdAndUpdate(
    { _id: bookID },
    {
      rating: { $divide: [{ $inc: { rating: Number(newRating) } }, 2] },
      $inc: { numOfRatings: 1 },
    },
    { new: true }
    );

and i am using postman to send client side data

here for example the rating field has previously set value of 4.1 and i am sending 5 as new rating in req.body then i want the rating field to have an updated value of 4.55 ((4.1 5)/2)

and this is the output i am getting in postman

{ "message": "Cast to Number failed for value "{ '$divide': [ { '$inc': [Object] }, 2 ] }" (type Object) at path "rating"", "stack": "CastError: Cast to Number failed for value "{ '$divide': [ { '$inc': [Object] }, 2 ] }" (type Object) at path "rating"\n at model.Query.exec (D:\Programs\VS Code\Web Development\lmsbackend\node_modules\mongoose\lib\query.js:4891:21)\n at model.Query.Query.then (D:\Programs\VS Code\Web Development\lmsbackend\node_modules\mongoose\lib\query.js:4990:15)\n at processTicksAndRejections (node:internal/process/task_queues:96:5)" }

i tried few things seeing mongodb solutions but it is not working out for me. Thank you in advance.

CodePudding user response:

$divide is only available for Aggregation framework, so you need to change your update (second) input like this:

db.collection.update({
  "_id": 1
},
[
  {
    "$set": {
      "rating": { "$divide": [{ "$sum": ["$rating", 5] }, 2] },
      "numOfRatings": { "$sum": ["$numOfRatings", 1 ] }
    }
  }
])

Working example

CodePudding user response:

To update the rating field, you can use the $avg operator instead of $divide:

const updateRating = await Book.findByIdAndUpdate(
    { _id: bookID },
    {
      rating: { $avg: [ "$rating", newRating ] },
      $inc: { numOfRatings: 1 },
    },
    { new: true }
    );

This will update the rating field with the average value of the existing rating and the new rating.

Note that you should also use the $inc operator to increment the numOfRatings field by 1.

Finally, make sure that the newRating value is cast to a Number before using it in the $avg operator. You can do this by using the Number() function.

const updateRating = await Book.findByIdAndUpdate(
    { _id: bookID },
    {
      rating: { $avg: [ "$rating", Number(newRating) ] },
      $inc: { numOfRatings: 1 },
    },
    { new: true }
    );

I hope this helps!

  • Related