skip to Main Content

I tried to using Filter() function in my NodeJs backend project, this is my function:

constructor(query, queryStr ){ 
    this.query = query; 
    this.queryStr = queryStr; } 
filter() { 
    const queryCopy = { ...this.queryStr }; 
    // Removing some fields for category 
    const removeFields = ["keyword", "page", "limit"];    
    removeFields.forEach((key) => delete queryCopy[key]);

    // Filter For Price and Rating

    let queryStr = JSON.stringify(queryCopy);
    queryStr = queryStr.replace(/b(gt|gte|lt|lte)b/g, (key) => `$${key}`);

    this.query = this.query.find(JSON.parse(queryStr));
    console.log(queryStr)
    
    return this;
  }

I am using postman to send request with the URL:
http://localhost:4000/api/v1/products?price%5Blt%5D=2000&price%5Bgte%5D=1200

It didn’t send any product, although I have a product with price=1200 in database, and another problem is when I log my (queryStr), it look like that:
{"price[$lt]":"2000","price[$gte]":"1200"}

What I expected is:
{"price":{[$lt]":"2000","[$gte]":"1200"}}

I think it is main reason to my problem, please help me.

2

Answers


  1. const a = {'price[lt]': 2000, 'price[gte]': 1200, 'other': 'parameters'};
    
    console.log(a); // { 'price[lt]': 2000, 'price[gte]': 1200 }
    
    let finalObject = {};
    for (const i of Object.keys(a)) {
        const key = i.match(/(price|amount)/)?.shift(); // modify your key params here ex: price, amount etc..
        const expr = i.match(/b(gt|gte|lt|lte)b/)?.shift();
        if (key && expr) {
            if (finalObject[key]) Object.assign(finalObject[key], { [`[$${expr}]`]: a[i] });
            else Object.assign(finalObject, { [key]: { [`[$${expr}]`]: a[i] }});
        } else Object.assign(finalObject, { [i]: a[i] });
    }
    console.log('finalObject...', finalObject); // {"price":{"[$lt]":2000,"[$gte]":1200},'other':'parameters'}
    
    Login or Signup to reply.
  2. You’ve correctly identified the issue with your filter function: the way the query string is transformed does not match MongoDB’s expected format for range queries. MongoDB expects range filters to be nested within the field they apply to, like so:

    {
      "price": {"$lt": 2000, "$gte": 1200}
    }
    

    However, after your transformation, the query becomes:

    {"price[$lt]":"2000","price[$gte]":"1200"}
    

    Which is not a valid MongoDB query for filtering based on a range. To fix this, you need to adjust your function to properly nest the operators within their respective fields. Here’s a modified version of your filter function that addresses this issue:

    filter() {
        const queryCopy = { ...this.queryStr };
    
        const removeFields = ["keyword", "page", "limit"];
        removeFields.forEach((key) => delete queryCopy[key]);
    
        let queryStr = JSON.stringify(queryCopy);
        queryStr = queryStr.replace(/b(gt|gte|lt|lte)b/g, match => `$${match}`);
    
        const parsedQuery = JSON.parse(queryStr);
        Object.keys(parsedQuery).forEach((key) => {
            const isRangeFilter = /b(gt|gte|lt|lte)b/.test(key);
            if (isRangeFilter) {
                const [field, operator] = key.split(/[[]]/); 
                if (!parsedQuery[field]) parsedQuery[field] = {};
                parsedQuery[field][operator] = parsedQuery[key];
                delete parsedQuery[key];
            }
        });
    
        this.query = this.query.find(parsedQuery);
        console.log(JSON.stringify(parsedQuery));
        
        return this;
    }
    

    By restructuring the query parameters in this manner, your function aligns with MongoDB’s expected input for range queries, which should resolve the issues you’re encountering.

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