skip to Main Content

I’m not sure how to deal with nested arrays and objects in JavaScript. I need to check if any of the Titles – whether the main folder Title or the Title within Contents – include a certain case-insensitive word (information in the sample code). It can stop checking as soon as it finds the word in any Title. I need to skip over/ignore the Description.

const data = [{
    "Title": "folder title 1",
    "Id": 857412,
    "Description": { "Text": "description 1" },
    "Contents": [
        { "Title": "contents 1 title 1", "Id": 123456 },
        { "Title": "contents 1 title 2 - Information", "Id": 987654 }
    ]
},{
    "Title": "folder title 2",
    "Id": 895623,
    "Description": { "Text": "description 2" },
    "Contents": [
        { "Title": "contents 2 title 3", "Id": 784512 }
    ]
}];

const contents = data.map(item => ({Contents:item.Contents}));
const folders = data.map(item => ({Title:item.Title}));
const combinedData = contents.concat(folders);
const stringData = JSON.stringify(combinedData);
console.log(stringData.toLowerCase().includes("information"));

My code works but I’m 100% sure that there is a better way to do this and I’m not sure how much data I’ll be dealing with each time. I just cannot wrap my head around the array of objects within an array of objects and I’m still too new to JavaScript to understand many methods. The examples on websites are too simplistic with just a few numbers in an array, which doesn’t help with this data.

What is a better method to use? How can I check the Titles for both folders and contents at the same time, while also ignoring Description, without needing to concatenate and stringify in order to find the word? Thanks for any suggestions!

2

Answers


  1. Don’t concatenate everything, just use Array.some() to search the arrays for a matching title in the top-level array or the nested Contents arrays. This will stop as soon as it finds a match.

    function titlesIncludes(data, search) {
      search = search.toLowerCase();
      return data.some(item =>
        item.Title.toLowerCase().includes(search) ||
        item.Contents.some(content => content.Title.toLowerCase().includes(search)));
    }
    
    console.log(titlesIncludes(data, "information"));
    console.log(titlesIncludes(data, "nothing"));
    <script>
      const data = [{
        "Title": "folder title 1",
        "Id": 857412,
        "Description": {
          "Text": "description 1"
        },
        "Contents": [{
            "Title": "contents 1 title 1",
            "Id": 123456
          },
          {
            "Title": "contents 1 title 2 - Information",
            "Id": 987654
          }
        ]
      }, {
        "Title": "folder title 2",
        "Id": 895623,
        "Description": {
          "Text": "description 2"
        },
        "Contents": [{
          "Title": "contents 2 title 3",
          "Id": 784512
        }]
      }];
    </script>
    Login or Signup to reply.
  2. Barmar’s nice answer specifically solves your question —
    speaking of folders having contents we could be easily speaking about Tree Nodes.
    Besides files, a folder’s Contents could also easily have sub-folders and so on, therefore here’s my two cents:

    create a recursive function that checks for deeply nested nodes

    /** Get Contents' node by key value; case-insensitive */
    const getNode = (arr = [], prop = "", val = "") => {
      for (const node of arr) {
        if (node[prop].toLowerCase().includes(val.toLowerCase())) return node;
        const res = getNode(node.Contents, prop, val);
        if (res) return res;
      }
    };
    
    // Use like:
    console.log(getNode(data, "Title", "information"));
    // Or like:
    if (getNode(data, "Title", "information")) { console.log("found"); };
    

    This way you can have as many nested Contents nodes as you want.
    As in this example:

    const data = [{
        "Title": "folder title 1",
        "Id": 857412,
        "Description": {
          "Text": "description 1"
        },
        "Contents": [{
            "Title": "contents 1 title 1",
            "Id": 123456
          },
          {
            "Title": "contents 1 title 2",
            "Id": 987654
          }
        ]
      },
      {
        "Title": "folder title 2",
        "Id": 895623,
        "Description": {
          "Text": "description 2"
        },
        "Contents": [{
          "Title": "contents 2 title 3",
          "Id": 784512
        }, {
          "Title": "SUBFOLDER",
          "Id": 999999,
          "Contents": [{
            "Title": "contents 3 title 3 - Information",
            "Id": 987654
          }]
        }]
      }
    ];
    
    /** Get Contents' node by key value; case-insensitive */
    const getNode = (arr = [], prop = "", val = "") => {
      for (const node of arr) {
        if (node[prop].toLowerCase().includes(val.toLowerCase())) return node;
        const res = getNode(node.Contents, prop, val);
        if (res) return res;
      }
    };
    
    console.log(getNode(data, "Title", "information"));
    if (getNode(data, "Title", "information")) {
      console.log("found");
    };
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search