Silent Storm
Silent Storm

Reputation: 69

$gte & $lte is not working as expected in Mongoose/MongoDB

I am filtering product list by price range. Some price range works fine and some doesn't. When I clicked (radio box) the price range in frontend, it gets processed in the backend via the pricelist. It looks like $gte and $lte not working as expected. Am I missing anything?

react frontend ---- pricelist :

export const prices = [
    {
        _id:0,
        name: 'Any',
        array: []
    },
    {
        _id:1,
        name: '$50 to $99',
        array: [50, 99]
    },
    {
        _id:2,
        name: '$100 to $199',
        array: [100, 199]
    },
    {
        _id:3,
        name: '$200 to $299',
        array: [200, 299]
    },
    {
        _id:4,
        name: '$300 to $399',
        array: [300, 399]
    },
    {
        _id:5,
        name: '$400 to $599',
        array: [400, 599]
    },
    {
        _id:6,
        name: '$600 to $799',
        array: [600, 799]
    },
]

NodeJS Backend -------- Product Search List :

exports.listBySearch = (req, res) => {
    let order = req.body.order ? req.body.order : "desc";
    let sortBy = req.body.sortBy ? req.body.sortBy : "_id";
    let limit = req.body.limit ? parseInt(req.body.limit) : 100;
    let skip = parseInt(req.body.skip);
    let findArgs = {};

    // console.log(order, sortBy, limit, skip, req.body.filters);
    // console.log("findArgs", findArgs);

    for (let key in req.body.filters) {
        if (req.body.filters[key].length > 0) {
            if (key === "price") {
                // gte -  greater than price [0-10]
                // lte - less than
                findArgs[key] = {
                    $gte: req.body.filters[key][0],
                    $lt: req.body.filters[key][1]
                };
                console.log(findArgs)
               // console.log -- { price: { '$gte': 50, '$lt': 99.99 } }
            } else {
                findArgs[key] = req.body.filters[key];
            }
        }
    }

    Product.find(findArgs)
        .select("-images")
        .populate("category")
        .sort([[sortBy, order]])
        .skip(skip)
        .limit(limit)
        .exec((err, data) => {
            if (err) {
                return res.status(400).json({
                    error: "Products not found"
                });
            }
            res.json({
                size: data.length,
                data
            });
        });
};

Mongoose --------- DB :

{
    "_id" : ObjectId("6079a8d675db7021c00aa973"),
    "sold" : 5,
    "name" : "Java Book for Everyone",
    "description" : "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
    "price" : "75",
    "category" : ObjectId("605c9c94dcf90b34e8ec33e0"),
    "shipping" : false,
    "quantity" : 7,
    "createdAt" : ISODate("2021-04-16T15:10:14.626Z"),
    "updatedAt" : ISODate("2021-04-16T15:10:14.626Z"),
    "__v" : 0
}

Upvotes: 2

Views: 1413

Answers (1)

Gabriel Lupu
Gabriel Lupu

Reputation: 1447

The price inside the mongoDB document is of type string. That's why query doesn't work. You want to cast the value of price inside mongo to number in order to compare. Modify the query to send something like this:

{
  $expr: {
    $and: [
      $gte: [{
        $toDouble: "$price"
      }, req.body.filters[key][0]],
      $lt: [{
        $toDouble: "$price"
      }, req.body.filters[key][1]]
    ]
  }
}

Upvotes: 1

Related Questions