简体   繁体   中英

Casting to number from query fails. Node.js Express Mongoose

I'm just starting out with Node Express MongoDb and API design and I'm trying to set up a rating system for products.

I added three fields:

totalRating: { type: Number, required: false },
    ratings: { type: Number, required: false },
    averageRating: {
        type: Number, required: false, default: function () {
            return this.totalRating / this.ratings
        }
    },

The Put Endpoint can either receive a body with the modified object (CRUD's Ùpdate), or receive a rating parameter which will be used to increment the totalRating parameter, that divided by ratings will calculate the average rating to display. If I pass a Number value directly ( $inc: { totalRating: 5 } it works as expected The problem is that getting the rating` query parameter to a number fails so the method throws an error:

rating is:  { rating: '4' }
Mongoose updateProductById rating error:  CastError: Cast to Number failed for value "NaN" (type number) at path "totalRating"
    at model.Query.exec (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/query.js:4470:21)
    at model.Query.Query.findOneAndUpdate (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/query.js:3122:8)
    at Function.Model.findOneAndUpdate (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/model.js:2520:13)
    at Function.Model.findByIdAndUpdate (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/model.js:2647:32)
    at exports.updateProductById (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/api/src/controllers/product.controller.js:399:13)
    at handleReturn (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
    at /Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:64:7
    at handleReturn (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
    at /Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:64:7
    at Layer.handle [as handle_request] (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express/lib/router/layer.js:95:5)
    at next (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express/lib/router/route.js:137:13)
    at exports.clientApiKeyValidation (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/api/src/auth_utils.js:15:9)
    at handleReturn (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
    at /Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:64:7
    at handleReturn (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:24:23)
    at /Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/express-promise-router/lib/express-promise-router.js:64:7 {
  messageFormat: undefined,
  stringValue: '"NaN"',
  kind: 'Number',
  value: NaN,
  path: 'totalRating',
  reason: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
  
    assert.ok(!isNaN(val))
  
      at castNumber (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/cast/number.js:28:10)
      at SchemaNumber.cast (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/schema/number.js:371:12)
      at SchemaNumber.SchemaType.applySetters (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/schematype.js:1106:12)
      at SchemaNumber.SchemaType._castForQuery (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/schematype.js:1584:15)
      at SchemaNumber.castForQuery (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/schema/number.js:425:14)
      at SchemaNumber.SchemaType.castForQueryWrapper (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/schematype.js:1551:20)
      at castUpdateVal (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/helpers/query/castUpdate.js:518:21)
      at walkUpdatePath (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/helpers/query/castUpdate.js:365:24)
      at castUpdate (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/helpers/query/castUpdate.js:95:7)
      at model.Query._castUpdate (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/query.js:4693:10)
      at castDoc (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/query.js:4723:18)
      at model.Query.Query._findAndModify (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/query.js:3602:22)
      at model.Query.<anonymous> (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/query.js:3139:8)
      at model.Query._wrappedThunk [as _findOneAndUpdate] (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/mongoose/lib/helpers/query/wrapThunk.js:16:8)
      at /Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/kareem/index.js:279:20
      at _next (/Volumes/ProjectsSSD/FixitServer/fixit_server_node/node_modules/kareem/index.js:103:16) {
    generatedMessage: true,
    code: 'ERR_ASSERTION',
    actual: false,
    expected: true,
    operator: '=='
  },
  valueType: 'number'
}

This is the Mongoose schema:

const productSchema = new mongoose.Schema({
    createdOnDate: {type: Number, required: true},
    name: {type: String, required: true},
    brand: {type: String, required: true},
    price: {type: Number, required: true},
    description: {type: String, required: true},
    category: {type: String, required: true},
    city: {type: String, required: true},
    region: {type: String, required: true},
    country: {type: String, required: true},
    vendor: {type: String, required: true},
    barcode: {type: String, required: true},
    imageUrl: {type: String, required: true},
    fullImages: {type: Array, required: true},
    thumbNails: {type: Array, required: true},
    // productImage: Uint8Array,
    minimumStock: {type: Number, required: true},
    availableQuantity: {type: Number, required: true},
    soldQuantity: {type: Number, required: true},
    totalRating:{type: Number, required: false},
    ratings:{type: Number, required: false},
    averageRating:{type: Number, required: false, default: function() {
        return this.totalRating / this.ratings
      }},

},
{ timestamps: true },);

and this is the updating method:

exports.updateProductById = async (req, res) => {

  const id = req.params.id;
  const rating = req.query;
  const updatedProduct = req.body;

  if (rating) {
console.log('rating is: ', rating);
const value = parseInt(rating);

    Product.findByIdAndUpdate(id,
      {
        $inc: { ratings: 1 },
        $inc: { totalRating: value }
        // $inc: { totalRating: 5 }  works perfectly
      },
      { new: true }, function (err, result) {
        if (err) {
          console.log('Mongoose updateProductById rating error: ', err);
          res.status(500).send({
            error: 'Internal error.'
          });
          return;
        }
        if (result != null) {
          console.log('Mongoose updateProductById rating: ', result);
          res.status(200).send({
            message: 'Product rating updated successfully!',
            data: result
          });
        }
        else {
          console.log('Mongoose updateProductById rating: No product found.');
          res.status(404).send({
            error: 'Product not found.'
          });

        }

      });

  } else {

    Product.findByIdAndUpdate(id, updatedProduct, { new: true }, function (err, result) {
      if (err) {
        console.log('Mongoose updateProductById error: ', err);
        res.status(500).send({
          error: 'Internal error.'
        });
      }
      if (result != null) {
        console.log('Mongoose updateProductById: ', result);
        res.status(200).send({
          message: 'Product updated successfully!',
          data: result
        });
      }
      else {
        console.log('Mongoose updateProductById: No product found.');
        res.status(404).send({
          error: 'Product not found.'
        });

      }

    });
  }
}

If you notice that when logging rating is equal to {rating: "4"} which is your req.query the value you want is actually req.query.rating so try something like

const rating = req.query.rating

or

const { rating } = req.query

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM