Ways to retrieve the value of each parent element within a nested array of objects

I have a complex array of objects where each object may contain nested children.

For example:

const data = [
    {
        id: 1,
        name: 'parent 1',
        children: [
            {
                id: 'c1',
                name: 'child 1',
                children: [
                    {
                        id: 'g1',
                        name: 'grand 1',
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 2,
        name: 'parent 2',
        children: [
            {
                id: 2,
                name: 'c1',
                children: [],
            },
        ],
    },
    { id: 3, name: 'parent 3', children: [] },
];

If I search for the ID 'g1', I want to get the result:

const result = ['parent 1', 'child 1', 'grand 1']

The loop should stop and return all the names it passed through until the condition (ID) is met.

Current Approach Implemented:

/**
 * Details
 * @param id the value you are searching for
 * @param items nested array of objects containing children
 * @param key name of the value being searched for
 * @returns an array of strings that match the id
 * @example ['parent 1', 'child 1', 'grand 1']
 */
export function findAll(id: string, items: any, key: string): string[] {
  let i = 0;
  let found;
  let result = [];

  for (; i < items.length; i++) {
    if (items[i].id === id) {
      result.push(items[i][key]);
    } else if (_.isArray(items[i].children)) {
      found = findAll(id, items[i].children, key);
      if (found.length) {
        result = result.concat(found);
      }
    }
  }
  return result;
}

Answer №1

I crafted this iterative solution that might be of assistance to you. It essentially navigates through the hierarchy and stores the path from the top level to the desired ID:

function findPath(obj, id) {
    // Initializing the stack to store the path
    let stack = obj.map(item => ({path: [item.name], currObj: item}));
    while (stack.length) {
        const {path, currObj} = stack.pop()
        if (currObj.id === id) {
            return path;
        } else if (currObj.children?.length) {
            stack = stack.concat(currObj.children.map(item => ({path: path.concat(item.name), currObj: item})));
        }
    }
    return null; // Return null if ID does not exist
}

This code assumes that your data structure is complete and does not have any missing parts (except possibly for children being null). By the way, do you believe your expected path should look like this:

["parent 1", "child 1", "grand 1"]

Answer №2

Presented below is a recursive function that performs the search.

const data = [
    {
        id: 1,
        name: 'parent 1',
        children: [
            {
                id: 'c1',
                name: 'child 1',
                children: [
                    {
                        id: 'g1',
                        name: 'grand 1',
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 2,
        name: 'parent 2',
        children: [
            {
                id: 2,
                name: 'c1',
            },
        ],
    },
    { id: 3, name: 'parent 3', children: [{}] },
];

function locatePath(object, search) {
    if (object.id === search) return [object.name];
    else if ((object.children) || Array.isArray(object)) {
        let children = Array.isArray(object) ? object : object.children;
        for (let child of children) {
            let result = locatePath(child, search);
            if (result) {
                if (object.id )result.unshift(object.name);
                return result;
            }
        }
    }
}

//const outcome = ['parent 1', 'c1', 'grand 1']
const outcome = locatePath(data, 'g1');
console.log(outcome);

Answer №3

To find a specific object in an array, you can create a recursive function that traverses the array while keeping track of the objects visited using a stack. When the function encounters an object with the desired id value (such as `g1`), it prints out the solution. Here's an example implementation:

'use strict';

function print(stack) {
    let result = "";
    stack.forEach(element => {
        result += element["name"] + " > ";
    });
    console.log(result + "\n");
}

function walkThrough(data, id, stack) {
    if (data !== undefined)
    for (let i = 0; i < data.length; i++) {
        const element = data[i];
        stack.push(element);
        if (element["id"] == id) print(stack);
        else walkThrough(element["children"], id, stack);            
    }
}

const data = [
    {
        "id": 1,
        "name": 'parent 1',
        "children": [
            {
                "id": 'c1',
                "name": 'child 1',
                "children": [
                    {
                        "id": 'g1',
                        "name": 'grand 1',
                        "children": [],
                    },
                ],
            },
        ],
    },
    {
        "id": 2,
        "name": 'parent 2',
        "children": [
            {
                "id": 2,
                "name": 'c1',
            },
        ],
    },
    { "id": 3, "name": 'parent 3', "children": [{}] },
];
//Calling the function to walk through the array...
walkThrough(data, 'g1', []);

Answer №4

Here is an alternative approach that may not be as elegant as the solutions mentioned above, but it gets the job done:

The method is simple: iterate with a for loop down to the 3rd level, and once a grandchild is found at that level, use break to exit all 3 levels of iteration.

I am intrigued by how different solutions would perform when dealing with a large dataset (let's say a million records).

let i=0, k=0, l=0;

let childrenLength = 0, grandChildrenLength = 0;

let result = [];
let foundGrandChild = false;

function searchGrandChild(searchString) {

  for (i; i< data.length; ++i) {
    if(data.length > 0){
      childrenLength = data[i].children.length;

      if(childrenLength > 0) {
        for (k; k < childrenLength; ++k) {

          if(data[i].children[k] != undefined) {
            grandChildrenLength = data[i].children[k].children.length;

            if(grandChildrenLength > 0) {
              for (l; l < grandChildrenLength; ++l) {
                if(data[i].children[k].children[l] != undefined) {

                  if(data[i].children[k].children[l].id === searchString) {
                    result.push(data[i].name);
                    result.push(data[i].children[k].id);
                    result.push(data[i].children[k].children[l].name);
                    foundGrandChild = true;
                    console.log('Yap, we found your grandchild 😊')
                    console.log(result);
                    break;
                  }
                }
                if(foundGrandChild) break;
              }

            }
          }
          if(foundGrandChild) break;
        }

      }
    }
    if(foundGrandChild) break;
  }

  if(!foundGrandChild) console.log('sorry, we could not find your grandchild 😮')
};

const data = [
    {
        id: 1,
        name: 'parent 1',
        children: [
            {
                id: 'c1',
                name: 'child 1',
                children: [
                    {
                        id: 'g1',
                        name: 'grand 1',
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 2,
        name: 'parent 2',
        children: [
            {
                id: 2,
                name: 'c1',
            },
        ],
    },
    { id: 3, name: 'parent 3', children: [{}] },
];


console.log('Let us search for "g1" ...');
searchGrandChild('g1');

console.log('Let us now search for "g2" ...');
foundGrandChild = false;
searchGrandChild('g2');

Answer №5

const data = [
  { id: "1234", parent_id: "", name: "jakson" },
  { id: "4567", parent_id: "1234", name: "obama" },
  { id: "7891", parent_id: "", name: "twinkel" },
  { id: "9876", parent_id: "1234", name: "behara" },
  { id: "1357", parent_id: "7891", name: "aaraku" },
  { id: "6789", parent_id: "7891", name: "mikel" },
  { id: "7892", parent_id: "4567", name: "aaraku" },
  { id: "8765", parent_id: "4567", name: "mikel" },
  { id: "9108", parent_id: "1234", name: "akshra" },
];
const createChildren = (data) => {
  return data.reduce((accumulator, value, index, array) => {
    const children = [];
    array.forEach((element) => {
      if (element.parent_id === value.id) {
        children.push({ id: element.id, name: element.name, parent_id: element.parent_id });
      }
    });
    return accumulator.concat({ ...value, children });
  }, []);
};
console.log(createChildren(data));

output:
(9) [{...}, {...}, {...}, {...}, {...}, ...]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
1
:
(4) {id: "4567", parent_id: "1234", name...}
2
:
(4) {id: "7891", parent_id: "", name: "t...}
3
:
(4) {id: "9876", parent_id: "1234", name...}
4
:
(4) {id: "1357", parent_id: "7891", name...}
5
:
(4) {id: "6789", parent_id: "7891", name...}
6
:
(4) {id: "7892", parent_id: "4567", name...}
7
:
(4) {id: "8765", parent_id: "4567", name...}
8`enter code here`
:
(4) {id: "9108", parent_id: "1234", name...}

Answer №6

let list = [
  { id: "1234", parent_id: "", name: "jakson" },
  { id: "4567", parent_id: "1234", name: "obama" },
  { id: "7891", parent_id: "", name: "twinkel" },
  { id: "9876", parent_id: "1234", name: "behara" },
  { id: "1357", parent_id: "7891", name: "aaraku" },
  { id: "6789", parent_id: "7891", name: "mikel" },
  { id: "7892", parent_id: "1234", name: "aaraku" },
  { id: "8765", parent_id: "1234", name: "aaraku" },
  { id: "9108", parent_id: "7891", name: "akshra" },
];

let newData = [];
let testing = [];
for (i = 0; i < list.length; i++) {
  if (!testing.includes(i)) {
    let y = list[i];
    for (j = i + 1; j < list.length; j++) {
      if (
        list[j].name === list[i].name &&
        list[j].parent_id === list[i].parent_id
      ) {
        Object.assign(y, list[j]);
        testing.push(j);
      }
    }
    newData.push(y);
  }
}
console.log(newData);
var parentChildList = [];
for (i = 0; i < newData.length; i++) {
  if (newData[i].parent_id === "") {
    parentChildList.push(newData[i]);
  }
}

for (i = 0; i < newData.length; i++) {
  for (j = 0; j < parentChildList.length; j++) {
    if (newData[i].parent_id === parentChildList[j].id) {
      if (parentChildList[j].child === undefined) {
        Object.assign(parentChildList[j], {
          child: [],
        });
        parentChildList[j].child.push(newData[i]);
      } else {
        parentChildList[j].child.push(newData[i]);
      }
    }
  }
}
console.log(parentChildList);

result:

(8) [{...}, {...}, {...}, {...}, {...}, ...]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
id
:
"1234"
parent_id
:
""
name
:
"jakson"
child
:
(3) [{...}, {...}, {...}]
0
:
(3) {id: "4567", parent_id: "1234", name...}
id
:
"4567"
parent_id
:
"1234"
name
:
"obama"
1
:
(3) {id: "9876", parent_id: "1234", name...}
id
:
"9876"
parent_id
:
"1234"
name
:
"behara"
2
:
(3) {id: "8765", parent_id: "1234", name...}
id
:
"8765"
parent_id
:
"1234"
name
:
"aaraku"
1
:
(3) {id: "4567", parent_id: "1234", name...}
id
:
"4567"
parent_id
:
"1234"
name
:
"obama"
2
:
(4) {id: "7891", parent_id: "", name: "t...}
id
:
"7891"
parent_id
:
""
name
:
"twinkel"
child
:
(3) [{...}, {...}, {...}]
0
:
(3) {id: "1357", parent_id: "7891", name...}
id
:
"1357"
parent_id
:
"7891"
name
:
"aaraku"
1
:
(3) {id: "6789", parent_id: "7891", name...}
id
:
"6789"
parent_id
:
"7891"
name
:
"mikel"
2
:
(3) {id: "9108", parent_id: "7891", name...}
id
:
"9108"
parent_id
:
"7891"
name
:
"akshra"
3
:
(3) {id: "9876", parent_id: "1234", name...}
id
:
"9876"
parent_id
:
"1234"
name
:
"behara"
4
:
(3) {id: "1357", parent_id: "7891", name...}
id
:
"1357"
parent_id
:
"7891"
name
:
"aaraku"
5
:
(3) {id: "6789", parent_id: "7891", name...}
id
:
"6789"
parent_id
:
"7891"
name
:
"mikel"
6
:
(3) {id: "8765", parent_id: "1234", name...}
id
:
"8765"
parent_id
:
"1234"
name
:
"aaraku"
7
:
(3) {id: "9108", parent_id: "7891", name...}
id
:
"9108"
parent_id
:
"7891"
name
:
"akshra"
(2) [{...}, {...}]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
id
:
"1234"
parent_id
:
""
name
:
"jakson"
child
:
(3) [{...}, {...}, {...}]

Answer №7

const elements = [
  { id: "1234", parent_id: "", name: "jakson" },
  { id: "4567", parent_id: "1234", name: "obama" },
  { id: "7891", parent_id: "", name: "twinkel" },
  { id: "9876", parent_id: "1234", name: "behara" },
  { id: "1357", parent_id: "7891", name: "aaraku" },
  { id: "6789", parent_id: "7891", name: "mikel" },
  { id: "7892", parent_id: `enter code here`"4567", name: "aaraku" },
  { id: "8765", parent_id: "4567", name: "mikel" },
  { id: "9108", parent_id: "1234", name: "akshra" },
];
const createChild = (elements) => {
  return elements.reduce((accumulator, value, index, array) => {
    const children = [];
    array.forEach((ele) => {
      if (ele.parent_id === value.id) {
        children.push({ id: ele.id, name: ele.name, parent_id: ele.parent_id });
      }
    });
    return accumulator.concat({ ...value, children });
  }, []);
};
console.log(createChild(elements));

output:
(9) [{...}, {...}, {...}, {...}, {...}, ...]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
1
:
(4) {id: "4567", parent_id: "1234", name...}
2
:
(4) {id: "7891", parent_id: "", name: "t...}
3
:
(4) {id: "9876", parent_id: "1234", name...}
4
:
(4) {id: "1357", parent_id: "7891", name...}
5
:
(4) {id: "6789", parent_id: "7891", name...}
6
:
(4) {id: "7892", parent_id: "4567", name...}
7
:
(4) {id: "8765", parent_id: "4567", name...}
8`enter code here`
:
(4) {id: "9108", parent_id: "1234", name...}

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

A guide to organizing page components across multiple `/pages` directories in a Next.js application

As I delve into my first project using Next.js, I find that my pages directory has expanded significantly. Now, I am keen on organizing my pages by grouping them into modules, resulting in a structure like 'src/modules/*/pages/*'. In my quest fo ...

There has been a mistake: The module '.... ode_modules erser-webpack-plugindistindex.js' cannot be found. Please ensure that the package.json file contains a correct "main" entry

After setting up Vue.js and executing npm run serve, I encountered the following error: PS C:\Amit\Demo\VUEDemo\myvue> npm run serve > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="98f5e1eeedfdd8a8b6 ...

How to delete URL parameters in JavaScript and HTML5

I have a URL that looks like this: /users/?i=0&p=90 How can I remove the part from ? to 90 Can anyone provide me with some JavaScript code to achieve this? EDIT I mean doing this with window.location.href directly in the browser URL bar. I trie ...

What could be causing the lack of population in ngRepeat?

In my angular application, I encountered an issue with ngRepeat not populating, even though the connected collection contains the correct data. The process involves sending an http get request to a node server to retrieve data, iterating over the server&a ...

Determine the absent information by comparing two JSON objects with JavaScript

Two JSON objects, counties and ctyIndem, are at hand. The counties object contains all the counties in a specific US State, while ctyIndem holds information about indemnities paid in that State by county, excluding those with no payments made. My task is t ...

Tips for personalizing a property within an array of objects in MongoDB

I am attempting to insert an object into an array where each object is required to have a unique name property. Below is the schema for my mongodb: db.createCollection("users", { validator: { $jsonSchema: { bsonType: "object", ...

Generate a fresh array using a current array comprising of objects

Greetings! I am facing a challenge with an array of objects like the one shown below: const data = [ {day: "Monday", to: "12.00", from: "15.00"}, {day: "Monday", to: "18.00", from: "22.00"}, {day: ...

Delete any additional input forms

I have recently developed a function to dynamically add an input field to my form: function add_parameter(){ var d = document.getElementById("content"); d.innerHTML += "<br/><br><div class='custom_search col-md-5'><sp ...

Showing C# File Content in JavaScript - A Step-by-Step Guide

Is there a way to showcase this File (c#) on a JavaScript site? return File(streams.First(), "application/octet-stream", Path.GetFileName(element.Path)); I am looking for something similar to this: <img id="myImg" src="_____&qu ...

"Add a hover effect to fade the image and make it clickable for a

Is there a way to make the entire image a clickable link when it's hovered over, rather than just the text inside? I could use some assistance with this. Javascript: $('.thumbnail').hover(function() { $('.thumbnail img').stop ...

Issue encountered while attempting to enclose a function within another function in Typescript

I'm attempting to wrap a function within another function before passing it to a library for later execution. However, I'm encountering various Typescript errors while trying to utilize .apply() and spread arguments. The library mandates that I ...

Accessing a single element from a nested object in Handlebars.js

Recently, I have been working on a nodejs application that utilizes handlebars js as its view engine. My main challenge at the moment is accessing one specific element from a nested object that I am passing to the hbs view. router.get('/view_users/:i ...

Unable to establish a connection with the default port on Mongo DB while utilizing Node.js

I am new to using Node.js and I'm trying to establish a connection with MongoDB in my Node.js application, but I'm encountering issues. Here is the code snippet: var mongo = require("mongodb"); var host="127.0.0.1"; var port=mongo.Connection.DE ...

Attempting to change the background color of a table row when hovering in React, but experiencing no success

Describing the appearance of my table row: <tr onMouseEnter={() => {this.buttonIsHovered = true} } onMouseLeave={() => {this.buttonIsHovered = false}} className={this.buttonIsHovered ? 'hover' : null}> The initial value ...

Removing all table rows except one in Jquery

I currently have this code in my view: <script> $(document).ready(function() { $("#add_instruction").click(function(){ $("#instructions").append("<tr><td></td><td><input type='text' name='rec ...

The function for batch insertion only functions with Postgresql and SQL Server databases

I am a beginner in JavaScript and I am currently working on creating a new restaurant. I have come across a code snippet that inserts a relation into a join-table: await newRestaurant.$relatedQuery('tags', trx).relate(tagIds); Is it not possible ...

Tips for simplifying a JavaScript function

Hello everyone, I just joined StackOverflow and I could really use some assistance with a JavaScript and jQuery issue that I'm facing. Can someone suggest a more efficient way to write the code below?: jQuery(document).ready(function () { $("#ar ...

The module '../xcode' could not be located. This issue is occurring within React Native and Expo CLI, where the required stack cannot

Trying my hand at creating my first project using React Native in iOS with expo.io, I encountered an error when running the command "expo start": https://ibb.co/f2xsmpN https://i.sstatic.net/Uyxkk.png Despite attempts to reinstall and update Xcode, usin ...

Engaging with JSON data inputs

Need help! I'm attempting to fetch JSON data using AJAX and load it into a select control. However, the process seems to get stuck at "Downloading the recipes....". Any insights on what might be causing this issue? (Tried a few fixes but nothing has w ...

Why won't JavaScript functions within the same file recognize each other?

So I have multiple functions defined in scriptA.js: exports.performAction = async (a, b, c) => { return Promise.all(a.map(item => performAnotherAction(item, b, c) ) ) } exports.performAnotherAction = async (item, b, c) => { console.log(`$ ...