Handling numeric filters on backend using ExpressJS and MongoDB

Photo by Tyler Nix on Unsplash

Handling numeric filters on backend using ExpressJS and MongoDB

·

3 min read

Working with numeric filters (Greater than or less than a certain amount)

Consider the following statement :

Product.find({prices:{$gt:30}})

Here $gt means greater than. Similarly $lt will mean less than. Product is the name of our schema we created using mongoose library.

If we are hard coding our API this is how our response can look like

const products = await Product.find({price:{$gt:30}}).select('name price').sort('price').limit(10).skip(2);

res.status(200).json({products, nbHits:products.length})

We are right now dealing with the numeric filter which we passed in the find() method. For handling the numeric filters we need to have an operator Map which should essentially map the string values to the corresponding syntax of MongoDB for making queries.

const operatorMap = {
            '>': '$gt',
            '>=': '$gte',
            '=': '$eq',
            '<': '$lt',
            '<=': '$lte',
        }

numericFilters=price>40,rating>=4 - This is how we will receive the numericFilters from our request and we have to handle the price and rating parameter( for this example).

We will first de-structure our req.query() object. If numericFilters is present we will use an operatorMap that will map the arithmetic operators(<|> etc.) to the mongoDB query parameters.

On getting the numericFilter in console, we will it returns a string, exactly like this 'price>40,rating>=4' which is passed in the URL. So we will use a regex to determine the presence of arithmetic operator.

In the regEx we will replace the arithmetic operator with '-' hyphen so that while we separate the arithmetic operators later, it becomes easy for us.

We need to split the string so we can operate on it.

We declare a regex which will take care of all the operators.

        const regEx = /\b(<|>|>=|=|<=)\b/g
        let filters = numericFilters.replace(regEx, (match) => {
            return `-${operatorMap[match]}-`
        })

Above statement will give us filters which will add hyphen before and after the arithmetic operator.

Once we have filters we will make an array of options which will contain the fields on which we will do the filtering. We are using the price and rating parameter hence options array will have 2 items only.

        const options = ['price', 'rating'];

        filters = filters.split(',').forEach(item => {
            // price-$gt-40 rating-$gte-4
            const [field, operator, value] = item.split('-');
            // price $gt 40
            if(options.includes(field)){
                queryObject[field] = {[operator] : Number(value)}
            }
        })

We are doing the following operations on filters,

1 . Splitting it from the point where we encounter ',' comma 2 . On splitting from the comma we will get a string 'price-$gt-40'. We will use this as item and again split it based on '-' hyphen 3 . Use array destructuring. We have 3 items every time the item string is split from hyphen. Use filed, operator and value for this example const [field, operator, value] = item.split('-');

For string 'price-$gt-40', field will be price; $gt will be operator and value will be '40' but as a string.

4 . Check in the options array that field exists or not. If field exists in the options array, we will populate the queryObject as per the MongoDB's correct syntax.

This way we can handle the numeric filtering required for our API. We can handle more and more filters based on the requirement, this example was based on a small project involving making a store API.