Home > Software engineering >  CastError: Cast to Number failed for value "{ '$lte': '100' }" (type O
CastError: Cast to Number failed for value "{ '$lte': '100' }" (type O

Time:09-07

So I have a mongo schema, which looks something like this:

const UserSchema = new mongoose.Schema({
  profile: {
    // ...other stuff
    age: {
      type: Number,
      min: [18, "Min age is 18"],
      max: [99, "Max age is 99"],
    },

And Im trying to query it through postman with the following: /users?profile.age[lte]=100

Other queries work, such as users?profile.age=36. This returns the correct number of results, as does users?profile.age[eq]=36. They both return the correct number of results.

In my controller I have:

export const getUsers = asyncHandler(async (req, res, next) => {
  let query;
  let queryStr = JSON.stringify(req.query);

  queryStr = queryStr.replace(
    /\b(gt|gte|lt|lte|in|elemMatch|eq)\b/g,
    (match) => `$${match}`
  );

  query = JSON.parse(queryStr);

  const users = await User.find(query);

  if (!users) {
    next(new ErrorResponse(`Unable to get users.`, 500));
  } else {
    res.status(200).json({
      success: true,
      count: users.length,
      data: users,
    });
  }
});

logging the query here gives me { 'profile.age': { '$lte': '36' } } which looks right to me

So basically every time I use lt lte gt gte it just throws this error in my face:

CastError: Cast to Number failed for value "{ '$lte': '36' }" (type Object) at path "profile.age" for model "User"

Any help much appreciated.

Thanks!

Edit: I also tried query-to-mongo in case I was handling the query incorrectly but it returns the same error.

Edit 2: Even just this:

  const users = await User.find({
    "profile.age": { $lte: 100 },
  });

Returns the error

CodePudding user response:

I was also facing the same problem. Mongoose cannot filter numeric string. So I came up with this idea. The below function checks upto 2 level. Hope this would work for you

const convertNumericStringToNumber = (obj) => {
  const res = {};
  for (const key in obj) {
    if (typeof obj[key] === "object") {
      res[key] = {};
      for (const prop in obj[key]) {
        const parsed = parseInt(obj[key][prop], 10);
        res[key][prop] = isNaN(parsed)
          ? obj[key][prop]
          : parsed;
      }
      continue;
    }
    const parsed = parseInt(obj[key], 10);
    res[key] = isNaN(parsed) ? obj[key] : parsed;
  }
  return res;
};

CodePudding user response:

So I got it working like this:

export const getUsers = asyncHandler(async (req, res, next) => {
  let query;
  let queryStr = JSON.stringify(req.query);

  queryStr = queryStr.replace(
    /\b(gt|gte|lt|lte|in|elemMatch|eq)\b/g,
    (match) => `$${match}`
  );

  query = JSON.parse(queryStr);

  const users = await User.aggregate([
    {
      $match: convertNumericStringToNumber(query),
    },
  ]);

  if (!users) {
    next(new ErrorResponse(`Unable to get users.`, 500));
  } else {
    res.status(200).json({
      success: true,
      count: users.length,
      data: users,
    });
  }
});

I'm not sure why User.aggregate works and User.find() doesn't work, but this seems to work in the exact same way.

  • Related