skip to Main Content

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

3

Answers


  1. Chosen as BEST ANSWER

    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.


  2. 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;
    };
    
    Login or Signup to reply.
  3. If you have sanitizeFilter set to true, set it back to false may solve this problem.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search