Access any nested node within a JSON/JS object by specifying the key's value

After spending hours searching on various forums for a solution to my problem, I have yet to find one that directly addresses the issue I am facing. So, please take a moment to review the details below.

The object structure in question is as follows:

let data = [{
   "id": 777,
   "name": "Level 1_section_1",
   "children": [{
       "id": 778,
       "name": "Level 2a",
       "children": [

       ]
     },
     {
       "id": 783,
       "name": "Level 2b",
       "children": [

       ]
     }
   ]
 },
 {
   "id": 786,
   "name": "Level 1_section_2",
   "children": [{
     "id": 781,
     "name": "Level 2c",
     "children": [

     ]
   }]
 }
]

In essence, each node's children property contains an array of nodes with the same structure.

If I want to locate the node with id:783, my first instinct would be to implement recursion. However, I am unsure how to ensure that this recursive function traverses the entire tree until it locates and returns the specific node I require so that I can add more children to it.

Although I come from a computer science background, my understanding of recursion is somewhat lacking.

This is the attempted solution I have implemented in my jsfiddle: https://jsfiddle.net/hanktrizz/surmf7dq/4/

Please bear in mind that the depth of the data tree may vary (although it should not exceed 8 or 9 levels) but I wanted to highlight this nonetheless.

Answer №1

One approach is to implement a recursive function with a for loop to find the desired node:

let data=[{id:777,name:"Level 1_section_1",children:[{id:778,name:"Level 2a",children:[]},{id:783,name:"Level 2b",children:[]}]},{id:786,name:"Level 1_section_2",children:[{id:781,name:"Level 2c",children:[]}]}];

const findNode = (arr, idToFind) => {
  for (const item of arr) {
    if (item.id === idToFind) {
      return item;
    }
    const possibleResult = findNode(item.children, idToFind);
    if (possibleResult) {
      return possibleResult;
    }
  }
};

console.log(findNode(data, 778));

Answer №2

Presented here is an enhanced findNode function that goes beyond searching by id exclusively. It now allows users to define a lambda function to search for nodes based on any condition -

findNode (n => n.id === 778, data)
// { id: 778, name: "Level 2a" }

findNode (n => n.name === "Level 2c", data)
// { id: 781, name: "Level 2c" }

findNode (n => n.id === 999, data)
// undefined

You can test the results in your own browser below -

const data =
    [{id:777,name:"Level 1_section_1",children:[{id:778,name:"Level 2a",children:[]},{id:783,name:"Level 2b",children:[]}]},{id:786,name:"Level 1_section_2",children:[{id:781,name:"Level 2c",children:[]}]}];

const None =
  Symbol ()

// findNode : (node -> boolean, node array) -> node?
const findNode = (f, [ node = None, ...nodes ]) =>
  node === None
    ? undefined
    : find1 (f, node) || findNode (f, nodes)

// find1 : (node -> boolean, node) -> node?
const find1 = (f, node = {}) =>
  f (node) === true
    ? node
    : findNode (f, node.children)

console.log (findNode (n => n.id === 778, data))
// { id: 778, name: "Level 2a" }

console.log (findNode (n => n.name === "Level 2c", data))
// { id: 781, name: "Level 2c" }

console.log (findNode (n => n.id === 999, data))
// undefined

In the code above, using destructuring assignment allows for a concise expression but introduces unnecessary intermediate values. The following revised version represents a significant enhancement -

// findNode : (node -> boolean, node array, int) -> node?
const findNode = (f, nodes = [], i = 0) =>
  i >= nodes.length
    ? undefined
    : find1 (f, nodes[i]) || findNode (f, nodes, i + 1)

// find1 : (node -> boolean, node) -> node?
const find1 = (f, node = {}) =>
  f (node) === true
    ? node
    : findNode (f, node.children)

Both versions provide short-circuit evaluation and will halt iteration as soon as the first result is found

Answer №3

Just for kicks, here's a code snippet that aims to retrieve all occurrences.

var data=[{id:777,name:"Level 1_section_1",children:[{id:778,name:"Level 2a",children:[]},{id:786,name:"Level 2b",children:[]}]},{id:786,name:"Level 1_section_2",children:[{id:781,name:"Level 2c",children:[]}]}]

var f = (o, pred, acc=[]) =>
  pred(o) ? [o] : Object.values(o).reduce((a, b) =>
    b && typeof b == 'object' ? a.concat(f(b, pred, acc)) : a, acc)

console.log(JSON.stringify(f(data, o => o.id == 781)))
console.log(JSON.stringify(f(data, o => o.id == 786)))

Answer №4

One approach to solving this problem is by utilizing object-scan

An advantage of this method is the ability to access additional data in the filterFn function for further processing. However, it does come with the trade-off of introducing a dependency.

// const objectScan = require('object-scan');

const myData = [{ id: 777, name: 'Level 1_section_1', children: [{ id: 778, name: 'Level 2a', children: [] }, { id: 783, name: 'Level 2b', children: [] }] }, { id: 786, name: 'Level 1_section_2', children: [{ id: 781, name: 'Level 2c', children: [] }] }];

const treeSearch = (data, id) => objectScan(['**(^children$)'], {
  useArraySelector: false,
  abort: true,
  rtn: 'value',
  filterFn: ({ value }) => value.id === id
})(data);

console.log(treeSearch(myData, 778));
// => { id: 778, name: 'Level 2a', children: [] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d6b9b4bcb3b5a2fba5b5b7b896e7e5f8e1f8e7">[email protected]</a>"></script>

Disclaimer: The author behind object-scan

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

tips for successfully transferring date and time data between json and nosql databases like firestore

Input: Created_At:Monday, 29 April 2019 15:07:59 GMT+05:30 Updated_At:Monday, 29 April 2019 15:07:59 GMT+05:30 I attempted to export data in JSON format from Firestore using the npm package firestore-export-import. However, the output I received was: ...

The JQuery-AJAX script in my Django application, intended to show a preset value in a calculated field, is not functioning as expected

Here are a couple of models from my project: class Package(models.Model): patient=models.ForeignKey(Patient, on_delete=CASCADE) diagnosis=models.ForeignKey(Diagnosis, on_delete=CASCADE) treatment=models.ForeignKey(Treatment, on_delete=CASCADE) ...

Checking for the existence of a row in Node.js using Sqlite3

Wondering if it's possible to verify the existence of a row using node.js and the sqlite module. I currently have this function in place, but it always returns false due to the asynchronous nature of the module. function checkIfRowExists(username, pa ...

Struggling to navigate the DOM using JavaScript and looking for guidance?

I have been searching for an answer to this question without any luck. I am wondering if someone can assist me with finding a solution... I need help using JavaScript (not jQuery) to retrieve the class of the following li element when searching for ' ...

Utilizing the components within the range set by paper.setStart() and paper.setFinish() in Raphaels

My question has two parts - the first and second part. Let's consider an example code that I am working on. I am creating a map of my country with regions, and I want to perform actions on the entire map such as scaling or translating (as seen in the ...

What is the best way to navigate back to the previous state in reactjs?

I have implemented a sidebar component with its initial state set to false in order to hide the block until a user interacts with the hamburger icon. Once clicked, the state changes to true and displays the sidebar menu. However, I am facing an issue whe ...

JavaScript placeholder-type expression

Hey there, I am a C++ developer who is venturing into the world of JavaScript. While exploring JavaScript syntax, I stumbled upon something that resembles templates in C++. For example, while going through RxJs tutorials, I came across this line of code: ...

Ways to implement the don't repeat yourself (DRY) principle in React JS with condition-based logic

https://i.stack.imgur.com/xkrEV.gif Here is a sample way to use the component: import React from "react"; import MyAvatars from "../../components/MyAvatar/MyAvatars"; const About = () => { return ( <MyAvatars ...

JQuery post request not providing the expected response after posting

I have a post request var prodId = getParameterByName('param'); var pass = $('#password1').val(); $.post("rest/forget/confirm", { "param" : prodId, "password" : pass }, function(data) { ...

JavaScript code for Tree not functioning correctly on Internet Explorer

Seeking assistance to fix a bug in my JavaScript program. The code works perfectly on Google Chrome and Firefox, however it encounters an error in Internet Explorer 8 as indicated below. Any suggestions on how to resolve this issue would be greatly appreci ...

What is the correct method for notifying the progress of time using jQuery?

I'm looking for a way to display the processing time of my PHP code using jQuery Here's an example of my PHP code : <?php //some queries to database ?> Below is my jQuery code: $.ajax({ type: "POST", url: "action. ...

When transmitting JSON data from the View to the Controller in ASP.NET MVC, the received values are

I'm facing an issue with sending JSON data from an MVC View to Controller. All I seem to get in the Controller is: https://i.sstatic.net/4pKNF.png The JSON I send in Url.Action looks like this: (I create it myself by adding arrays together using .pu ...

Submitting forms using Ajax within a modal pop-up box

Here's an interesting issue that I'm facing: On a test page, when the user clicks to view results, a modal box opens with 3 select boxes. Select Box 1 populates Select Box 2, which then populates Select Box 3 The Problem: After clicking submi ...

Menu secured in place within the wrapper

My website is contained in a wrapper with a max width, and I have a fixed side menu that can be toggled with a button. The problem I am facing is keeping the fixed side menu within the page wrapper. Fixed elements are typically positioned relative to the ...

Ensuring the safety of PHP JSON output results on a web server

I am currently developing an app using phonegap that submits and retrieves data from a MySQL database hosted on a server (website). I have successfully implemented the data submission and retrieval features in the app. The data is fetched through AJAX fro ...

Raspberry Pi 4: My LED is only blinking 8 times instead of the expected 16 times

I have encountered an issue with my program run, compilation, and result. In the screenshot below, you can see that my LED is only blinking 8 times instead of the anticipated 16 times. My expectation was for the LED to blink every 0.25 seconds for a total ...

Tips for utilizing Selenium Webdriver to input text into a webpage textbox using onblur, onfocus, and onkeydown attributes

I'm looking to streamline the process of inputting a value into a text box on a webpage, similar to automating my timesheet. The HTML code for the text box is shown below. <input type="text" class="" onblur="return setValue(this);" title="Time"; ...

Retrieving Json data results in a boolean outcome

I am working on a code snippet that includes a switch statement which returns true or false, as well as an if and else statement for further validation. The goal is to send a value through an input field using ajax and have PHP return true or false based o ...

What is the best way to create a dynamic JavaScript counter, like one that counts the world's population

Can someone guide me on creating a real-time JavaScript count-up feature that doesn't reset when the page reloads? Any tips or examples similar to would be much appreciated. Thank you! ...

The functionality of the handleTextShow function in components>DrinkList.js is not working as expected after integrating an API

While working on my react program, I created a DrinkList.js file to display images of drinks. However, when I attempted to make the images clickable by adding an Onclick function to display their names in the console, errors started flooding in. import Rea ...