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.