Filtering an object based on data available in another object


#1

I am struggling with filtering an array of partners. Just for the sake of simplicity, I am defining partner object as below:

var partners = [
  { partnerCategory: "Gold", programs: ["Enterprise"] },
  { partnerCategory: "Silver", programs: ["Core", "Enterprise"] },
  { partnerCategory: "Silver", programs: ["Enterprise"] }
];

Now there are 2 picklists: partnerCategory and programs. If the user selects any value from the picklist, then I am populating an object filterCriteria.

Now I am defining filterCriteria in various ways to get an idea of the records that should be returned.

OPTION 1

var filterCriteria = [
   { fieldName: "partnerCategory", fieldValue: ["Silver"] }
];

2nd and 3rd record should be returned.

OPTION 2

var filterCriteria = [
   { fieldName: "partnerCategory", fieldValue: ["Silver", "Gold"] }
];

No record should be returned

OPTION 3

var filterCriteria = [
   { fieldName: "partnerCategory", fieldValue: ["Silver"] },
   { fieldName: "programs", fieldValue: ["Enterprise"] }
];

2nd and 3rd records should be returned.

OPTION 4

var filterCriteria = [
   { fieldName: "partnerCategory", fieldValue: ["Silver"] },
   { fieldName: "programs", fieldValue: ["Enterprise", "Core"] }
];

Only 2nd record should be returned.

So basically if a value is present in filterCriteria object, then the record should have all the values present in the filter.

I am using the below code to get the output, but I am missing something:

var result = partners.filter(function (obj) {
    return filterCriteria.every(function (c) {
        var value = obj[c.fieldName];
        if (typeof value === 'object') {
            return Object.keys(value).every(function (key) {
                return c.fieldValue.indexOf(value[key]) > -1
            })
        }
        else
            return c.fieldValue.indexOf(value) > -1
    })
});

#2

That returns true if value matches any criterion, but IIUC you want it to match every criterion... i.e.

return c.fieldValue.every(function (fieldValue) {
  return fieldValue === value
})

#3

The code is still not working. I feel that I have made some mistake in the lines below:

if (typeof value === 'object') {
            return Object.keys(value).every(function (key) {
                return c.fieldValue.indexOf(value[key]) > -1
            })
        }

When filterCriteria = [
{ fieldName: "partnerCategory", fieldValue: ["Silver"] },
{ fieldName: "programs", fieldValue: ["Enterprise", "Core"] }
];

then for fieldName programs, it should check both the values, i.e. Enterprise and Core, in partners object.


#4

Watch the comparison operators (> vs ===)! ;-) Here's a slightly refactored (although not strictly equivalent) version that yields the desired results:

var filter = function (list, criteria) {
  return list.filter(function (item) { 
    return criteria.every(function (criterion) {
      var value = item[criterion.fieldName]
      
      return criterion.fieldValue.every(function (fieldValue) {
        return Array.isArray(value) 
          ? value.includes(fieldValue) 
          : value === fieldValue
      })
    })
  })
}

var result = filter(partners, searchCriteria)

JS bin


closed #5

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.