Transform an array of objects into a nested tree structure with Javascript

I am currently facing a challenge with handling a complex json file using javascript to structure it hierarchically. My goal is to convert an array of objects into a deeply nested array, where there can be multiple divNames with varying categories and subcategories.

Here is the initial array of objects:

[
{
   divName: "ABC",
   divId: 123,
   catName: "XYZ",
   catId: 456,
   subCatName: "PQR"
   subCatId: 781
},
{
   divName: "ABC",
   divId: 123,
   catName: "YQP",
   catId: 281,
   subCatName: "FYI"
   subCatId: 231
},
{
   divName: "ABC",
   divId: 123,
   catName: "XYZ",
   catId: 456,
   subCatName: "YAB"
   subCatId: 587
}
]

The expected output should look like this:

[{divName: "ABC",
  divId: 123
  categories: [
     {
       catName: "XYZ",
       catId: 456,
       subCategories: [
         {
            subCatName: "PQR",
            subCatID: 781
         },
         {
            subCatName: "YAB",
            subCatID: 587
         }
       ]
     },
     {
       catName: "YQP",
       catId: 281,
       subCategories: [
         {
           subCatName: "FYI"
           subCatID: 231
         }
       ]
     }]
  ]

Currently, my progress on handling this conversion is as follows:

nonCompetitorData.map((data, idx) => {
            if(idx === 0) {
                downloadData.push({"divisionName": data.divisionName, "divisionId": data.divisionId});
            } else {
                if (!downloadData[0].categories) {
                    downloadData[0].categories = [];
                    downloadData[0].categories.push({
                        "categoryName": data.categoryName,
                        "categoryId": data.categoryId
                    })
                } else {
                    if(downloadData[0].categories) {
                        if(!downloadData[0].categories.some(c => c.categoryName === data.categoryName)) {
                            downloadData[0].categories.push({
                                "categoryName": data.categoryName,
                                "categoryId": data.categoryId
                            })
                        }
                    }
                    downloadData[0].categories.forEach((cat, i) => {
                        if(!cat.subCategories) {
                            console.log("Categories",downloadData[0].categories[i]);
                            downloadData[0].categories[i].subCategories = [];
                            downloadData[0].categories[i].subCategories.push({
                                "subCategoryName": data.subCategoryName,
                                "subCategoryId": data.subCategoryId
                            });
                        } else {
                            if(cat.subCategories) {
                                if(!cat.subCategories.some(c => c.subCategoryName === data.subCategoryName)) {
                                    downloadData[0].categories[i].subCategories.push({
                                        "subCategoryName": data.subCategoryName,
                                        "subCategoryId": data.subCategoryId
                                    })
                                }
                            }
                        }
                    });
                }
            }
        });

I am open to suggestions for a more efficient way to achieve this. Any insights?

Answer №1

To retrieve already added nodes to the tree, you can utilize both Array::reduce and a map. In case your div, cat, subcat IDs are not unique together, simply append a prefix of d for divs and c for cats when working with the map.

const result = array.reduce((map => (result, {divId,divName,catId,catName,subCatId,subCatName}) => {
  const {categories: cats} = map[divId] ??= result[result.length] = {divName, divId, categories:[]};
  (map[catId] ??= cats[cats.length] = {catName, catId, subcategories:[]})
    .subcategories.push({subCatName, subCatId});
  return result;
})({}), []);

console.log(result);
<script>
const array = [{
   divName: "ABC",
   divId: 123,
   catName: "XYZ",
   catId: 456,
   subCatName: "PQR",
   subCatId: 781
},
{
   divName: "ABC",
   divId: 123,
   catName: "YQP",
   catId: 281,
   subCatName: "FYI",
   subCatId: 231
},
{
   divName: "ABC",
   divId: 123,
   catName: "XYZ",
   catId: 456,
   subCatName: "YAB",
   subCatId: 587
}
]
</script>

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

What's up with this unconventional jQuery formatting? Can someone shed some light on

I recently found a plugin that toggles checkboxes, but unfortunately it's not functioning correctly with the latest version of jQuery so I'm currently working on debugging it. Could someone please provide an explanation for the following code sn ...

Receiving multiple NodeJS Responses through AJAX for a single request

I have been working on a WebApp that involves heavy AJAX calls from the frontend and NodeJS Express at the backend. Here is a glimpse of my Frontend Code- Below is the global AJAX function I consistently use in all my projects: function _ajax(params = {}, ...

Randomizing the JSON loop on every page refresh

Having a JSON file containing various data items (as an example) that I am utilizing with handlebars.js to generate templates. The challenge lies in displaying 15 stories (each within their own div) on page load while shuffling their positions upon each r ...

The function purported by WEBPACK_MODULE_13___default(...) does not exist

Scenario : I've been working on a small library (let's call it myLibrary) using TypeScript and Webpack. Everything seemed to be running smoothly until I imported the library into a React application, which resulted in a crash. On the Library Sid ...

Utilize JavaScript/jQuery to implement a prompt for saving downloaded files

Is it possible to use javascript or jquery to configure the setting mentioned above (Ask where to save each file before downloading)? ...

Retrieving data from a React state in one component and utilizing it in a separate component

Thank you for taking the time to assist me with this challenge. I am currently working on a project that involves creating the state goodData in one component called AddProduct and accessing it in another component named ActionBox, both within the same j ...

Tips for avoiding problems with quoting and using apostrophes in a JavaScript function inside a tag in a JSP file

Within my JSP, I have a string value stored in ${state.status.code} that I need to pass to a JavaScript function when a table element is clicked using onClick to trigger the showStatus function. Here is how I have attempted to achieve this: <c:set var= ...

Error: Unable to update Ember Array - Property 'destroy' cannot be read because it is undefined

Is there a way to efficiently update an Ember Array so that changes in the array reflect in the view? Take a look at this simplified code snippet - cacheArr: Em.A([]), count: 1, updateFxn: function() { this.incrementProperty(count); devObj = Embe ...

What are some ways to adjust the size of the option field in a select menu?

In my ionic popup, I have a HTML property called select with nested options. Below is the code snippet along with the applied CSS. My query is how can I set the white space to occupy the entire area of the select? https://i.stack.imgur.com/iPqAa.png http ...

Receive a notification when the div element stops scrolling

I am attempting to replicate Android's expandable toolbar within an Angular component. My HTML code appears as follows: <div (scroll)="someScroll($event)"> <div class="toolbar"></div> <div class="body"></div> </d ...

What is the process for displaying all cookies in node.js?

I recently wrote some node.js code to retrieve cookies for a specific route. router.get('/', function (req, res, next) { var cookies = req.cookies; res.render('cartoons', { Cookies: cookies, }); }); In my cartoons Jade file, the ...

Tips for setting up a Vue.js property as an array type element

To begin, I am looking to initialize the properties of image, description, video, and title with the corresponding fields from the first element in the variants array. The variants array is retrieved by sending an AJAX request that returns a JSON file. ...

The functionality of returning false on ajax response does not effectively prevent the form from submitting

I'm encountering an issue where the return false statement doesn't seem to work when using an AJAX call. The form is still getting submitted successfully despite trying to prevent it with a conditional check on the response from the AJAX request. ...

Python's dynamic numpy arrays deliver flexibility and efficiency

I am attempting to create a numpy array (let's call it A) with a shape of (a, b, 1, d) where the value of d is unknown and varies depending on the input I receive. Additionally, I have another array (which we'll refer to as B) with the shape (a, ...

The Javascript query is returning an [object Object] data type

I am facing an issue with a JavaScript file that is querying a SharePoint list. Specifically, the Priority drop down in the query result is displaying as [object OBJECT]. I suspect it has something to do with the var query string where I have added the &ap ...

Exciting discovery within my coding for US Number formatting!

I am currently working on formatting 10 digits to resemble a US telephone number format, such as (###) ###-####. Although my code successfully achieves this goal, it also has an unexpected issue that I'm struggling to identify. Specifically, when ente ...

Methods for applying responsive design to react modals in React.js

I am looking to make my modal responsive across different media types. In my React JS project, I have implemented custom styles using the following code: import Modal from 'react-modal'; const customStyles = { content : { top ...

What is the method for retrieving a JSON type object property that is stored inside a data object in a Vue template?

I am facing an issue with retrieving data from a Vue.js app object. data() { return { group1: { id: 'qd4TTgajyDexFAZ5RKFP', owners: { john: {age: 32, gender: 'man'}, mary: {age: 34, gender: 'wom ...

The page remains static even as the function is executed

Having trouble with creating a sliding form using jQuery. The issue is that instead of sliding to the desired page, it slides to a blank one. The website where this problem can be seen is www.entrilab.com. Upon inspecting the element, there are no errors ...

Using Nested ng-repeat for Values and Keys in Angular

Struggling with implementing nested ng-repeats in my code. I have a JSON object with multiple layers and attempting to iterate through them to display the data. Here is the structure of the JSON: { "status": "success", "data": { "Mat": { "tota ...