0

I need to filter in deep the categories object inside an array, in an array with multiple objects. In an API call , I will have this array of objects with nested categories. I need to filter each object if it contains specific category id. This is the JSON -

items_loop: [
  {
    ID: 1,
    name: "Item A",
    taxonomy: {
      categories: [
        {
          name: "Book",
          parent: 12,
          taxonomy: "category",
        },
        {
          name: "Cover",
          parent: 4,
          taxonomy: "category",
        },
        {
          name: "Other",
          parent: 15,
          taxonomy: "category",
        },
      ],
    },
  },
  {
    ID: 2,
    name: "Item B",
    taxonomy: {
      categories: [
        {
          name: "Toys",
          parent: 16,
          taxonomy: "category",
        },
        {
          name: "Book",
          parent: 12,
          taxonomy: "category",
        },
        {
          name: "Other",
          parent: 15,
          taxonomy: "category",
        },
      ],
    },
  },
  {
    ID: 3,
    name: "Item C",
    taxonomy: {
      categories: [
        {
          name: "Ext",
          parent: 6,
          taxonomy: "category",
        },
        {
          name: "Cover",
          parent: 4,
          taxonomy: "category",
        },
        {
          name: "Other",
          parent: 15,
          taxonomy: "category",
        },
      ],
    },
  },
]

I want to make a new array with object that contains only "parent" : 15, but how I can filter in deep this 3 object ? I tried with this, but it's not working

function findInObjArray(array, value) {
  var found = []

  // Helper to search obj for value
  function findInObj(obj, value) {
    return Object.values(obj).some((v) =>
      // If v is an object, call recursively
      typeof v == "object" && v != "null"
        ? findInObj(v, value)
        : // If string, check if value is part of v
        typeof v == "string"
        ? v.indexOf(value) >= 0
        : // Check numbers, make NaN == NaN
        typeof v == "number"
        ? v === value || (isNaN(v) && isNaN(value))
        : // Otherwise look for strict equality: null, undefined, function, boolean
          v === value
    )
  }

  array.forEach(function (obj) {
    if (findInObj(obj, value)) found.push(obj)
  })

  return found
}
1
  • condition ? val1 : val2 : val3 is invalid syntax. Commented Aug 27, 2020 at 15:52

2 Answers 2

1

You mean something like this - filter arrays that is inside objects that is in your main array? You can iterate your array of object as you wish and do filter in cycle. Or use map method as in example below:

const obj = [{
      ID: 1,
      name: 'Item A',
      taxonomy : {
        categories : [{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 2,
      name: 'Item B',
      taxonomy : {
        categories : [{
            name: "Toys",
            parent: 16,
            taxonomy: "category",
          },{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 3,
      name: 'Item C',
      taxonomy : {
        categories : [{
            name: "Ext",
            parent: 6,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
}];
  
// Map and filter nested content
const res = obj.map(a => {
  a.taxonomy.categories = a.taxonomy.categories.filter(x => x.parent === 15);
  return a;
});
  
// Log
console.log(res)

Or if you mean you want to filter your main array to only contain object that has nested array with some value - then this is little modification of previous code

const obj = [{
      ID: 1,
      name: 'Item A',
      taxonomy : {
        categories : [{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 2,
      name: 'Item B',
      taxonomy : {
        categories : [{
            name: "Toys",
            parent: 16,
            taxonomy: "category",
          },{
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
    },{
      ID: 3,
      name: 'Item C',
      taxonomy : {
        categories : [{
            name: "Ext",
            parent: 6,
            taxonomy: "category",
          },{
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },{
            name: "Other",
            parent: 15,
            taxonomy: "category",
        }]
      }
}];
  
// Map and filter nested content
const res = obj.filter(a => {
  if((a.taxonomy.categories.filter(x => x.parent === 6)).length > 0) return a;
});
  
// Log
console.log(res)

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

Comments

0

The code below should return an array of only item objects in which the nested categories array has been filtered for matches.

Note that:

  • Only items containing at least 1 matching category are returned (meaning if an item didn't contain any matching categories, it will not be present in the output).
  • Only matching categories are present in the output.
  • If categoryFilterFunc returns no matches across all items and categories, the return value will be an empty array.

const obj = {
  items_loop : [
    {
      ID: 1,
      name: 'Item A',
      taxonomy : {
        categories : [
          {
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },
          {
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },
          {
            name: "Other",
            parent: 15,
            taxonomy: "category",
          },                                                                              
        ]
      }
    },
    {
      ID: 2,
      name: 'Item B',
      taxonomy : {
        categories : [
          {
            name: "Toys",
            parent: 16,
            taxonomy: "category",
          },
          {
            name: "Book",
            parent: 12,
            taxonomy: "category",
          },
          {
            name: "Other",
            parent: 15,
            taxonomy: "category",
          },                                                                              
        ]
      }
    },
    {
      ID: 3,
      name: 'Item C',
      taxonomy : {
        categories : [
          {
            name: "Ext",
            parent: 6,
            taxonomy: "category",
          },
          {
            name: "Cover",
            parent: 4,
            taxonomy: "category",
          },
          {
            name: "Other",
            parent: 15,
            taxonomy: "category",
          },             
        ]
      }
    },                      
  ]
};

function filterCategories(someObject, categoryFilterFunc) {
  return someObject.items_loop.reduce((accum, item) => {
    const filtered = item.taxonomy.categories.filter(categoryFilterFunc);
    if (filtered.length > 0) {
      // Creating a deep copy will have some performance impact (depending on
      // how many items and nested categories you need to iterate over)
      // but seems advisable for nested objects. Up to you if you
      // want to keep it.
      const deepCopy = JSON.parse(JSON.stringify(item));
      deepCopy.taxonomy.categories = filtered;
      accum.push(deepCopy);
    }
    return accum;
  }, []);
}

const matchingItems = filterCategories(obj, categoryObj => 15 === categoryObj.parent);

console.log(matchingItems);

1 Comment

Thank you chillin, it work but in the Api call i've a lot of object. I prefeer to user the map method below. Thank you for help!

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.