Search code examples
javascriptarray-filter

Filter object array based on nested array filter criteria and return new map props along with filter result nested object


How to get filter nested data and result map to new props name. Please have look at below codesandbox.

https://codesandbox.io/s/es6-filter-sub-data-and-return-new-obj-d9s0o1?file=/src/index.js

Have tried with below approach but its not getting filter for child objects.

console.log(getFilterData("type2"));        
function getFilterData(type) {

  var r = data.filter((d) => d.subs.some((s) => s.type === type));
  console.log(r);
  /* expected to return: (only return "type2" filter result with 
  some new map "prop key" name)
  {
    id: 1,
    name: "name_1",
    subModule: [ {
      id: "sub_2",
      type: "type2"
    },
    {
      id: "sub_3",
      type: "type2"
    }]
  }
  */
}

var data = [
  {
    id: 1,
    name: "name_1",
    subs: [
      {
        id: "sub_1",
        name: "sub_1",
        type: "type1"
      },
      {
        id: "sub_2",
        name: "sub_2",
        type: "type2"
      },
      {
        id: "sub_3",
        name: "sub_3",
        type: "type2"
      }
    ]
  },
  {
    id: 2,
    name: "name_2",
    subs: [
      {
        id: "sub_11",
        name: "sub_11",
        type: "type3"
      },
      {
        id: "sub_21",
        name: "sub_21",
        type: "type1"
      }
    ]
  }
];

Solution

  • You can map your data to a new array which has objects with the subs array filtered on type, then filter that array by the length of the subs array:

    var data = [
      {
        id: 1,
        name: "name_1",
        subs: [
          { id: "sub_1", name: "sub_1", type: "type1" },
          { id: "sub_2", name: "sub_2", type: "type2" },
          { id: "sub_3", name: "sub_3", type: "type2" }
        ]
      },
      {
        id: 2,
        name: "name_2",
        subs: [
          { id: "sub_11", name: "sub_11", type: "type3" },
          { id: "sub_21", name: "sub_21", type: "type1" }
        ]
      }
    ];
    
    const getFilterData = (data, type) =>
      data
        .map(o => ({...o, subs : o.subs.filter(s => s.type == type) }))
        .filter(o => o.subs.length)
        
    console.log(getFilterData(data, 'type2'))

    If you want to change the name of the subs array in the process, change the map and filter to:

    .map(({subs, ...rest}) => ({...rest, subModule : subs.filter(s => s.type == type) }))
    .filter(o => o.subModule.length)
    

    Also, if you want to remove the name field from subs, change

    subs.filter(s => s.type == type)
    

    to

    subs.filter(s => s.type == type).map(({name, ...rest}) => ({...rest}))
    

    Updated code with both changes:

    var data = [
      {
        id: 1,
        name: "name_1",
        subs: [
          { id: "sub_1", name: "sub_1", type: "type1" },
          { id: "sub_2", name: "sub_2", type: "type2" },
          { id: "sub_3", name: "sub_3", type: "type2" }
        ]
      },
      {
        id: 2,
        name: "name_2",
        subs: [
          { id: "sub_11", name: "sub_11", type: "type3" },
          { id: "sub_21", name: "sub_21", type: "type1" }
        ]
      }
    ];
    
    const getFilterData = (data, type) =>
      data
        .map(({subs, ...rest}) => ({
          ...rest, 
          subModule : subs.filter(s => s.type == type).map(({name, ...rest}) => ({...rest}))
        }))
        .filter(o => o.subModule.length)    
    console.log(getFilterData(data, 'type2'))