javascriptarraysformsapifiltering

Best way to filter an objects's properties for data


I'm trying to filter some API data via a search form but unsure how to get the desired results and not sure where I'm going wrong.

I'm calling an API which returns an array of objects that looks like this:-

const apiData = [
    {
        "firstName": "chris",
        "lastName": "kundill",
        "postcode": "sa11 3fj"
    },
    {
        "firstName": "sam",
        "lastName": "white",
        "postcode": null
    },
    {
        "firstName": "john",
        "lastName": "davies",
        "postcode": "sa11 3fj"
    },
    {
        "firstName": "jane",
        "lastName": "davies",
        "postcode": "sa11 3fj"
    },
    {
        "firstName": "maria",
        "lastName": "davies",
        "postcode": "sa11 3fj"
    },
    {
        "firstName": "nutter",
        "lastName": "dave",
        "postcode": "sa11 3fj"
    },
    {
        "firstName": "donna",
        "lastName": "duggie",
        "postcode": "sa11 3fj"
    }
]

I have stored the search form data in an object and that looks like this, NB. not all 3 input fields have to be filled :-

const formData = {
    "firstName": "Chris",
    "postcode": "SA11 3FJ"
}

I then take the formData object and convert the values to lowercase and remove any empty strings by doing this :-

const sanitise = Object.values(formData).map((item) => {
      return item.toLowerCase()
    }).filter((item) => {
      if (item !== '') {
        return item
      }
    })

giving me:-

const sanitise = ['chris', 'sa11 3fj']

How can I filter the API data to return the correct object containing the sanitise array data?

I've been using the array.filter method but I can't find the correct combination of conditions to return the correct object only, without it returning every object containing a "postcode": "sa11 3fj"


Solution

  • If you keep your form data as an object after sanitising it you can check its key/value pairs against every object in the dataset without hardcoding keys in your search function.

    const data=[{firstName:"chris",lastName:"kundill",postcode:"sa11 3fj"},{firstName:"sam",lastName:"white",postcode:null},{firstName:"john",lastName:"davies",postcode:"sa11 3fj"},{firstName:"jane",lastName:"davies",postcode:"sa11 3fj"},{firstName:"maria",lastName:"davies",postcode:"sa11 3fj"},{firstName:"nutter",lastName:"dave",postcode:"sa11 3fj"},{firstName:"donna",lastName:"duggie",postcode:"sa11 3fj"}];
    
    // `reduce` over the formData entries.
    // If the current prop value exists coerce it
    // to lowercase (and add the property to the accumulator)
    function sanitiseFormData(formData) {
      const formEntries = Object.entries(formData);
      return formEntries.reduce((acc, [ key, value ]) => {
        if (value) acc[key] = value.toLowerCase();
        return acc;
      }, {});
    }
    
    // `search` accepts the data, and the sanitised query
    // `filter` over the data and for each object iterate over
    // the queryEntries and if every one of the key/value pairs in
    // the query matches the key/value pairs in the current object
    // return the object
    function search(data, query) {
      const queryEntries = Object.entries(query);
      return data.filter(obj => {
        return queryEntries.every(([ key, value ]) => {
          return obj[key] === value;
        });
      });
    }
    
    const formData1 = {
      firstName: 'Chris',
      lastName: '',
      postcode: 'SA11 3FJ'
    };
    
    const formData2 = {
      firstName: 'Donna',
      lastName: null,
      postcode: 'SA11 3FJ'
    };
    
    console.log(search(data, sanitiseFormData(formData1)));
    console.log(search(data, sanitiseFormData(formData2)));

    Additional documentation