0

I am trying to write a search function that can search through an array of arrays of objects and return any objects that include the search string in the name.

The issue I am having is that the object array can contain an array of children and the children can also have an array of children. I need to dynamically search through all the possible children and return the results

I have tried to do this with Algolia but because the file structure won't be constantly updated I feel this would be better using Array.includes or something similar

I have tried the following function but can't seem to get it working

  searchArray(subMenuItems, name) {
    if (subMenuItems) {
      for (let i = 0; i < subMenuItems.length; i++) {
        if (subMenuItems.includes(name)) {
          return subMenuItems[i];
        }
        const found = this.getSubItem(subMenuItems[i].children, name);
        if (found) {
          return found;
        }
      }
    }
  }

Here is an example of the Object Array

[
   [
      {
         "children":[
            {
               "children":[
                  {
                     "fileSize":"1.2MB",
                     "fileUrl":"https://linktoPDF.com",
                     "name":"GF Kitchen ",
                     "type":"file"
                  }
               ],
               "name":"Ground Floor Kitchen",
               "type":"folder"
            }
         ],
         "name":"House",
         "type":"folder"
      }
   ],
   [
      {
         "fileSize":"1.3MB",
         "fileUrl":"https://linktoPDF.com",
         "name":"Introduction and Overview",
         "type":"file"
      },
      {
         "fileSize":"20MB",
         "fileUrl":"https://linktoPDF.com",
         "name":"VISUAL iPad Location Drawing",
         "type":"file"
      },
      {
         "fileSize":"1MB",
         "fileUrl":"https://linktoPDF.com",
         "name":"Control Surface",
         "type":"file"
      },
      {
         "fileSize":"1.3MB",
         "fileUrl":"https://linktoPDF.com",
         "name":"Scene",
         "type":"file"
      }
   ]
]
  • Please also include what you have tried so far. Your example seems like Json to me. – Bosco Jun 22 '19 at 04:32
  • Updated with the function I am trying to get working – Josh Marcus Jun 22 '19 at 04:34
  • Let's start from here https://stackoverflow.com/questions/2722159/how-to-filter-object-array-based-on-attributes – Bosco Jun 22 '19 at 04:39
  • Yeah I get that but how can I search through all the possible children and children of children without knowing how many children or children of children there will be in the object – Josh Marcus Jun 22 '19 at 04:41

2 Answers2

1

A simple recursive function will allow you to gather the objects (or any property from the object) from each of the nested (no matter how deeply) objects.

You should consider whether case sensitivity is something that is important too.

Otherwise, this will work:

  • Search data for any name with 'ce'
  • then search for any name with 'tion'
  • then search for any name with 'Floor'

const data = [[{"children":[{"children":[{"fileSize":"1.2MB","fileUrl":"https://linktoPDF.com","name":"GF Kitchen","type":"file"}],"name":"Ground Floor Kitchen","type":"folder"}],"name":"House","type":"folder"}],[{"fileSize":"1.3MB","fileUrl":"https://linktoPDF.com","name":"Introduction and Overview","type":"file"},{"fileSize":"20MB","fileUrl":"https://linktoPDF.com","name":"VISUAL iPad Location Drawing","type":"file"},{"fileSize":"1MB","fileUrl":"https://linktoPDF.com","name":"Control Surface","type":"file"},{"fileSize":"1.3MB","fileUrl":"https://linktoPDF.com","name":"Scene","type":"file"}]];
let output = [];

function search(arr, str) {
  arr.forEach(a => {
    if (a.constructor == Array) {
      search(a, str);
    } else if (a.children) {
      if (a.name.includes(str)) output.push(a);
      search(a.children, str);
    } else {
      if (a.name.includes(str)) output.push(a);
    }

  });
}
search(data, 'ce');
console.log(output);
output = [];
search(data, 'tion');
console.log(output);
output = [];
search(data, 'Floor');
console.log(output);
Randy Casburn
  • 13,840
  • 1
  • 16
  • 31
0

You can try a recursive function as below to check the array and the children array to get the result.

function searchByName(obj, name) {
  if (Array.isArray(obj)) {
    return obj.reduce((acc, item) => acc.concat(searchByName(item, name)), []);
  }
  if (typeof obj === 'object') {
    const matched = [];
    const { children, ...rest } = obj;
    if (obj.name && obj.name.includes(name)) {
      matched.push(rest);
    }
    return Array.isArray(children) ?
      matched.concat(searchByName(children, name)) : matched;
  }
  return;
}

const arr = [[{"children":[{"children":[{"fileSize":"1.2MB","fileUrl":"https://linktoPDF.com","name":"GF Kitchen","type":"file"}],"name":"Ground Floor Kitchen","type":"folder"}],"name":"House","type":"folder"}],[{"fileSize":"1.3MB","fileUrl":"https://linktoPDF.com","name":"Introduction and Overview","type":"file"},{"fileSize":"20MB","fileUrl":"https://linktoPDF.com","name":"VISUAL iPad Location Drawing","type":"file"},{"fileSize":"1MB","fileUrl":"https://linktoPDF.com","name":"Control Surface","type":"file"},{"fileSize":"1.3MB","fileUrl":"https://linktoPDF.com","name":"Scene","type":"file"}]];

console.log(searchByName(arr, 'not found'));
console.log(searchByName(arr, 'Drawing'));
console.log(searchByName(arr, 'S'));
fyasir
  • 2,924
  • 2
  • 23
  • 36