Home > Net >  How to filter array of objects with nested objects with specific properties?
How to filter array of objects with nested objects with specific properties?

Time:06-02

I am trying to filter a Javascript array of objects with nested objects with specific properties. I can filter the name, slug, website, launch year without any issues. But, I can not filter the category name (category.name) which is an object within the object. Why is filtering the category name not working?

            var search = "qui"; // does not work (category.name)
            // var search = "Sauer"; // works (name)

            var data = [{ "name": "Sauer-Metz", "slug": "ab-laborum", 
              "website": "https://test.com", "launch_year": 2017,  "category_id": 6,
              "category": { "id": 6, "name": "qui", "slug": "qui" } } ];

            var results = data.filter(company => [
                'name', 'launch_year', 'website', 'category.name'
            ].some(key => String(company[key]).toLowerCase().includes(search.toLowerCase())));

            console.log(results);

CodePudding user response:

I believe you have to do a separate condition for this specific nested property, although there might be a cleaner way I don't see right now:

var results = data.filter(
  (company) =>
    ["name", "launch_year", "website"].some((key) =>
      String(company[key]).toLowerCase().includes(search.toLowerCase())
    ) ||
    String(company["category"]["name"])
      .toLowerCase()
      .includes(search.toLowerCase())
);

CodePudding user response:

One way you can go about it is to have a value extractor like the one getKey below

const getKey = (value, key) => {
    return key.split('.').reduce((acc, curr) => value[curr], '');
 }
 
 

 var results = data.filter(company => [
            'name', 'launch_year', 'website', 'category.name'
        ].some(key => String(getKey(company, key)).toLowerCase().includes(search.toLowerCase())));

CodePudding user response:

Dot notation doesn't work like that.

const testCase1 = 'qui';
const testCase2 = 'Sauer';

const data = [
    {
        name: 'Sauer-Metz',
        slug: 'ab-laborum',
        website: 'https://test.com',
        launch_year: 2017,
        category_id: 6,
        category: { id: 6, name: 'qui', slug: 'qui' },
    },
];

const searchResults = (data, search) => {
    return data.filter((item) => {
        return (
            item?.category?.name.toLowerCase().includes(search.toLowerCase()) ||
            ['name', 'launch_year', 'website'].some((key) => `${item[key]}`.toLowerCase().includes(search.toLowerCase()))
        );
    });
};

console.log('**CASE 1**')
console.log(searchResults(data, testCase1));
console.log('**CASE 2**')
console.log(searchResults(data, testCase2));

CodePudding user response:

To use your approach you can convert 'category.name' to ['category','name'] and then use String(company[key[0]][key[1]])... whenever key is an array.

const search = "qui"; // does not work (category.name)
//const search = "Sauer"; // works (name)

const data = [{ "name": "Sauer-Metz", "slug": "ab-laborum",  "website": "https://test.com", "launch_year": 2017,  "category_id": 6, "category": { "id": 6, "name": "qui", "slug": "qui" } } ];

const results = data.filter(
    company => [
        'name', 'launch_year', 'website', ['category','name']
    ].some(
        key => 
        Array.isArray(key) ?
        String(company[key[0]][key[1]]).toLowerCase().includes(search.toLowerCase()) : 
        String(company[key]).toLowerCase().includes(search.toLowerCase())
    )
);

console.log(results);

  • Related