1

I have a filtersArray which is a bunch of {id, value} and I want to filter my data (also array of JSON objects) to get back only the elements that match all of the filters? Is there a better way to do this than iterating through the arrayOfFilters with each filter using a for loop and doing a filter on each criteria?

the data is an array of JSON objects - ie

[{formID:1234, name:"sam", email:"[email protected]", status:"open", phone: "333-444-5555"},
 {formID:2155, name:"charlie", email:"[email protected]", status:"closed", phone: "888-323-1234"},...]

and the filtersArray [{"status":"closed"}, {"name":"charlie"}, {"id":2155}...]

I have tried doing

for(var criteria in arrayOfFilters){
   this.data = this.data.filter( d => d.status === criteria.status)
                    .filter(d => d.name === criteria.name)
                    .filter(d => d.address === criteria.address)...
}

it does not work real well since criteria is a JSON object like {"status":"closed"}, {"name":"charlie"}...

6
  • 6
    Show what have you tried so far in terms of code Commented Feb 14, 2020 at 19:49
  • 2
    Can show your arrays Commented Feb 14, 2020 at 19:52
  • updated with more details Commented Feb 14, 2020 at 20:05
  • 2
    Please add an example of the filters array. Commented Feb 14, 2020 at 20:09
  • why you need to check all criteria, there is an id that is used for that i think... Commented Feb 14, 2020 at 20:31

4 Answers 4

4

If the idea is to find all items of source array that match (by all properties) with some item of filter array, you can go like that:

const srcArr = [{formID:1234,name:"sam",email:"[email protected]",status:"open",phone:"333-444-5555"},{formID:2155,name:"charlie",email:"[email protected]",status:"closed",phone:"888-323-1234"}],
      filterArr = [{status:'closed', name:'charlie'}],
      result = srcArr.filter(srcItem => 
                  filterArr.some(filterItem => 
                    Object.entries(filterItem).every(([filterKey, filterValue]) => 
                      srcItem[filterKey] == filterValue)))
    
console.log(result)
.as-console-wrapper {min-height:100%}

If your filter is a plain object, that's even more simple:

const srcArr = [{formID:1234,name:"sam",email:"[email protected]",status:"open",phone:"333-444-5555"},{formID:2155,name:"charlie",email:"[email protected]",status:"closed",phone:"888-323-1234"}],
      filterObj = {name:'charlie', status:'closed'}
      result = srcArr.filter(srcItem => 
                Object.entries(filterObj).every(([filterKey, filterVal]) => 
                  srcItem[filterKey] == filterVal))
      
console.log(result)
.as-console-wrapper {min-height:100%}

Sign up to request clarification or add additional context in comments.

2 Comments

Looking closer, the answer is a bit off. Your filterArr is an array of object of strings when it should be an array of objects which each have a separate string. ie [{"status":"closed"}, {"name":"charlie"}, {"id":2155}...]
@Linkx_lair : if source array objects should match to every object of filterArr, simply replace some() with every(). You didn't really need to revoke your accept I would gladly support you with above solution, so the comment was pretty enough to draw my attention ;)
1

You need this I believe, Find the key in the filters object and compare it to every record you come across in your data object. Once you have the key you can easily check the values

const arrayToFilter = [{
  id: 1,
  name: 'sam'
}, {
  id: 1,
  status: 'open'
}, {
  id: 1,
  name: 'ana'
}];
const data = [{
    formID: 1234,
    name: "sam",
    email: "[email protected]",
    status: "open",
    phone: "333-444-5555"
  },
  {
    formID: 1234,
    name: "mara",
    email: "[email protected]",
    status: "open",
    phone: "333-444-5555"
  },
  {
    formID: 1234,
    name: "eugen",
    email: "[email protected]",
    status: "close",
    phone: "333-444-5555"
  }, {
    formID: 1234,
    name: "kevin",
    email: "[email protected]",
    status: "close",
    phone: "333-444-5555"
  },
  {
    formID: 1234,
    name: "ana",
    email: "[email protected]",
    status: "close",
    phone: "333-444-5555"
  }
]


const result = data.filter(x => {
  return arrayToFilter.some(y => {
    const key = Object.keys(y)[1];
    return y[key] === x[key]
  })
});
console.log(result)

1 Comment

I want to get an array of objects from data that match all the criteria in arrayToFilter. There is a redundant 'name' attribute in the arrayToFilter - which should result in no matches as it is an invalid filter. Other than that it looks real interesting
0

if id is unique u can do:

const filteredArray = arrayOfData.filter( data => arrayOfFilters.map( filter => filter.id ).includes( data.id ) )

Comments

0
const result = arrayOfData.filter( 
                     data => arrayOfFilters.map(d =>d.status).includes(data.status))&& 
                             arrayOfFilters.map(d =>d.name).includes(data.name))&&
                             arrayOfFilters.map(d =>d.address).includes(data.address) )
                                 )

Or

let result = []
for(var criteria in arrayOfFilters){
 result.push(this.data.filter( d => d.status === criteria.status && 
                                    d.name === criteria.name &&
                                    d.address === criteria.address)...
}

2 Comments

Thanks hamid. The issue i am running into is if there is an empty criteria attribute like no name. ie if the arrayOfFilters has a status or address but no name, then the filter doesn't return the object even if the other attributes match it. Is there a way to do this using maps and filters and other array functions more dynamically instead of using the for loop?
It depends on what you want to do after viewing an empty criteria attribute.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.