Search code examples
javascriptjqueryjsonjavascript-objects

Apply a filter with multiple values in javascript object


I am working on a filter with javascript. I have a json object of all data and filters in json as well. I need to apply that filter with between for example filter all the data which has price between 50-100.

Sample data is like this

var filterEvents = [
    {id:1,price:25},
    {id:2,price:45},
    {id:3,price:57},
    {id:4,price:80},
    {id:5,price:105},
    {id:6,price:200}
    ];

Filters json looks like this

var budgets =["1","2","3","4","5"]; // 1 for <30 , 2 for 31-50, 3 for 51-100, 4 for 101-150, 5 for 151+

Filter json can have any number of data

I am trying it with this if else condition.

var filterEvents = [
{id:1,price:25},
{id:2,price:45},
{id:3,price:57},
{id:4,price:80},
{id:5,price:105},
{id:6,price:200}
];

//var budgets =["1","2","3","4","5"]; // 1 for <30 , 2 for 31-50, 3 for 51-100, 4 for 101-150, 5 for 151+
var budgets =["1","2","3"];
//var budgets =["1","2"];
//var budgets =["1"];
if(budgets.includes('1') && !budgets.includes('2')&& !budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 30  ;
                                  });
}
else if(budgets.includes('1') && budgets.includes('2')&& !budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 50   ;
                                  });
}

else if(budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 100   ;
                                  });
}

else if(budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 150   ;
                                  });
}

else if(budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    
}

if(!budgets.includes('1') && !budgets.includes('2')&& !budgets.includes('3')&& !budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >150  ;
                                  });
}

if(!budgets.includes('1') && !budgets.includes('2')&& !budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >100  ;
                                  });
}

if(!budgets.includes('1') && !budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >50  ;
                                  });
}

if(!budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >30  ;
                                  });
}

if(budgets.includes('1') && !budgets.includes('2')&& budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <=30 || element.price >50 && element.price<100 ;
                                  });
}

if(budgets.includes('1') && !budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <=30 || element.price >50 ;
                                  });
}

console.log(filterEvents);

Here is the working JSfiddle

The issue in this code is a will need to add all the conditions and it could stop working for some data. I am finding a more accurate solution.


Solution

  • You can use the Array.prototype.filter() Method to remove any non-matching elements.

    Although it is neccessary for more automation, that you have some definition of your Budget-Values as you have written as a comment in your source code. Like a table or an array storing the conditions for each value.

    const budgetCondition = {
      '1': (value) => value <= 30,
      '2': (value) => value >= 31 && value <= 50,
      '3': (value) => value >= 51 && value <= 100,
      '4': (value) => value >= 101 && value <= 150,
      '5': (value) => value >= 151
    };
    

    This is an Object with indexes matching your Values in your budgets-Array. As Values i've use Arrow-Functions (normal function(value){ Boolean operation ...} would be sufficient too) stored where we would provide the comparing budgetValue against and retrieve the Boolean value if this value should be kept or be removed.

    Then you could iterate through all set Budget-Filters and grab the necessary filterCondition from the budgetCondition-Object.

    let filteredData = filterEvents.filter(item => {
      let filtered = !!budgets.find(filterIndex => {
        if (budgetCondition[filterIndex](item.price)) return true;
        return false;
      });
      return filtered;
    });
    

    With filterEvents.filter() we iterate through all Items of the array and remove any Elements, which returns false in the Callback function. To determine which elements we want to keep and returning true, we use the Array.prototype.find() Method.
    This then iterates through all filterIndexes set and checks if the current element should be kept.
    To achieve this, we use the previously defined filterCondition Object by accessing the corresponding condition-Function with the filterIndex.

    We then provide the Price-value and will get a boolean value if this price matches the condition.
    If it matches we keep this element and return a true for the filter-Method.


    Down below i've added a snippet demonstrating the complete procedure.
    Keep in mind, that if you want to add further conditions, you have to include those with an Index in the conditions object with a function, which will return a boolean value if the condition is met.

    var filterEvents = [{
        id: 1,
        price: 25
      },
      {
        id: 2,
        price: 45
      },
      {
        id: 3,
        price: 57
      },
      {
        id: 4,
        price: 80
      },
      {
        id: 5,
        price: 105
      },
      {
        id: 6,
        price: 200
      }
    ];
    
    var budgets = ["3", "4", "5"];
    
    
    
    function filterData(data, budgets) {
      // We define an Object like structure for our definitions, how to filter
      // We match the index to our values in the budgets-Array and associate a function
      // which will resolve into a boolean value if the condition well be met.
      const budgetCondition = {
        '1': (value) => value <= 30,
        '2': (value) => value >= 31 && value <= 50,
        '3': (value) => value >= 51 && value <= 100,
        '4': (value) => value >= 101 && value <= 150,
        '5': (value) => value >= 151
      };
    
      // We then want to filter out all elements, that doesn't fit any set filters.
      return filterEvents.filter(item => {
    
        // We check if the current checking element will met any filters set in our budgets-Array
        // This Method would return the first matching filterIndex, that resolves to a true condition
        // but with the doulbe Exclamation mark we convert this result into a boolean value.
        let filtered = !!budgets.find(filterIndex => {
    
          // We check each FilterIndex thats set in the budgets-Array and access the corresponding       // condition function in our budgetCondition-Object.
          // If the Function resolved to true, we return the fulfilling filterIndex, therefore  
          // signaling, that the Element matches a filter and should be kept.
          // 
          // As a Comment pointed out, we have to check if the filterIndex matches any filter in 
          // our condition Object. If not, we ignore the check
          if (budgetCondition[filterIndex] && budgetCondition[filterIndex](item.price)) return true;
    
          // If it didnt resolve the function to true, we return false, therefore signaling that this 
          // filterCondition wasnt met and are looking further.
          return false;
        });
    
        // If we have found a matching filter this will return true. If we have iterated through all 
        // set budgetFilters and none of them resolved to true, we will return a false and therefore 
        // filter out this element.
        return filtered;
      });
    }
    
    console.log("First Filter: ",filterData(filterEvents, ["1", "2", "3"]));
    console.log("First Filter: ",filterData(filterEvents, ["3", "4", "6"]));