How to filter nested arrays by searching

Viewed 697

I have an array of objects that I want to filter by comparing a nested property to a search term.

For example:

let array = [
  {
    category: 15,
    label: "Components",
    value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
    children: [
      {
        category: 1,
        label: "Carousel1",
        diId: 55946,
        // as you can see there are many children nested array of object
        children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
        value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
      },
      {
        category: 2,
        label: "Checkbox1",
        diId: 193909,
        children: [{ label: "datafound", value: "47d18sb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
        value: "045e8786-2165-4e1e-a839-99b1b0ceef57"
      }
    ]
  },
  {
    value: "4be22726-850c-4905-ab3b-039fcf607d55",
    label: "Default",
    children: [
      {
        category: 5,
        defaultValueType: 1,
        label: "Empty",
        toType: "String",
        value: "ebedb43f-4c53-491f-8954-d030321845cd"
      },
      {
        category: 5,
        defaultValueType: 2,
        label: "Space",
        toType: "String",
        value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
      },
      {
        category: 5,
        defaultValueType: 8,
        label: "Current Username",
        toType: "String",
        value: "25f6b40a-33c7-4f17-b29d-99e8d1e4e33c"
      },
      {
        category: 5,
        defaultValueType: 9,
        label: "Current Location",
        toType: "Location",
        value: "ed59da2f-318d-4599-9085-4d9d769a27d7"
      }
    ]
  },
  {
    category: 4,
    label: "Fixed Value",
    isFixed: true,
    value: "28e90e3e-a20b-4499-9593-061a7d1e7bd6"
    // as you can see there is no children in this object
  }
]};

What I'm trying to achieve is if I search for 'nodata' for example my result should be

let array = [
  {
    category: 15,
    label: "Components",
    value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
    children: [
      {
        category: 1,
        label: "Carousel1",
        diId: 55946,
        // as you can see there are many children nested array of object
        children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
        value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
      }
    ]
  }
];

Another option if I search for 'spa' my result should be

let array = [
  {
    value: "4be22726-850c-4905-ab3b-039fcf607d55",
    label: "Default",
    children: [
      {
        category: 5,
        defaultValueType: 2,
        label: "Space",
        toType: "String",
        value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
      }
    ]
  }
];

I have been super confused and I decided to get some help. Thank you for your helps guys!

1 Answers

The following function should do the trick for you:

function searchData(dataArray, searchTerm) {
  return dataArray.flatMap(obj => {
    const objHasSearchTerm = Object.entries(obj)
      .some(([key, value]) => key !== 'children' && String(value).toLowerCase().includes(searchTerm.toLowerCase()));
    
    if (objHasSearchTerm && !obj.children) return [obj];
    
    const matchedChildren = searchData(obj.children ?? [], searchTerm);
    return objHasSearchTerm || matchedChildren.length > 0
      ? [{
        ...obj,
        children: matchedChildren,
      }]
      : [];
  })
}

It recursively goes through the data array, looks for any entries that have the specified search term, and if so, places it into the newly constructed object. It will preserve the nested shape of the object, which may or may not be what is needed. Feel free to tweak the algorithm to your own needs.

let allData = [
  {
    category: 15,
    label: "Components",
    value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
    children: [
      {
        category: 1,
        label: "Carousel1",
        diId: 55946,
        // as you can see there are many children nested array of object
        children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
        value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
      },
      {
        category: 2,
        label: "Checkbox1",
        diId: 193909,
        children: [{ label: "datafound", value: "47d18sb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
        value: "045e8786-2165-4e1e-a839-99b1b0ceef57"
      }
    ]
  },
  {
    value: "4be22726-850c-4905-ab3b-039fcf607d55",
    label: "Default",
    children: [
      {
        category: 5,
        defaultValueType: 1,
        label: "Empty",
        toType: "String",
        value: "ebedb43f-4c53-491f-8954-d030321845cd"
      },
      {
        category: 5,
        defaultValueType: 2,
        label: "Space",
        toType: "String",
        value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
      },
      {
        category: 5,
        defaultValueType: 8,
        label: "Current Username",
        toType: "String",
        value: "25f6b40a-33c7-4f17-b29d-99e8d1e4e33c"
      },
      {
        category: 5,
        defaultValueType: 9,
        label: "Current Location",
        toType: "Location",
        value: "ed59da2f-318d-4599-9085-4d9d769a27d7"
      }
    ]
  },
  {
    category: 4,
    label: "Fixed Value",
    isFixed: true,
    value: "28e90e3e-a20b-4499-9593-061a7d1e7bd6"
    // as you can see there is no children in this object
  }
];



function searchData(dataArray, searchTerm) {
  return dataArray.flatMap(obj => {
    const objHasSearchTerm = Object.entries(obj)
      .some(([key, value]) => key !== 'children' && String(value).toLowerCase().includes(searchTerm.toLowerCase()));
    
    if (objHasSearchTerm && !obj.children) return [obj];
    
    const matchedChildren = searchData(obj.children ?? [], searchTerm);
    return objHasSearchTerm || matchedChildren.length > 0
      ? [{
        ...obj,
        children: matchedChildren,
      }]
      : [];
  })
}

console.log('----- Search: nodata')
console.log(JSON.stringify(searchData(allData, 'nodata'), null, 2))
console.log('----- Search: spa')
console.log(JSON.stringify(searchData(allData, 'spa'), null, 2))

Related