Using JavaScript to group an array of objects by a specific key

I'm struggling to group my array of objects into another desired array based on a specific property. Despite checking out various tutorials, I couldn't achieve the expected output.

What I aim for is to group all elements according to their designated properties.

Below is my input:

permissions= [
    {
      code: 'U00',
      permission_name: 'Read User',
      groupBy: 'User',
      icon: 'user',
    },
    {
      code: 'U01',
      permission_name: 'Create User',
      groupBy: 'User',
      icon: 'user',
    },
  
    {
      code: 'B00',
      permission_name: 'Read Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B01',
      permission_name: 'Create Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B10',
      permission_name: 'Update Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
  ];

Desired output:

 Output = [
    {
      label: 'User',
      icon: 'user',
      children: [
        {
          label: 'Create Users',
        },
        {
          label: 'Read All Users',
        },
      
      ],
    },
    {
      label: 'Batch',
      children: [
        {
          label: 'Create Batchs',
        },
        {
          label: 'Read All Batch',
        },
        {
          label: 'Update Batch',
        },
        {
          label: 'Disabled Batch',
        },
      ],
    },
  ];

Answer №1

[curItem.groupBy]To improve your code, consider utilizing the reduce method. Visit this link for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

return Object.values(permissions.reduce((curObj, curItem) => { 
  if(!curObj.hasOwnProperty(curItem.groupBy)){
    curObj[curItem.groupBy] = { 
      label: curItem.label, 
      icon: curItem.icon, 
      children: [] 
    };
  }
  curObj[curItem.groupBy].children.push({ label: curItem.label });
  return curObj;
}, {}));

Answer №2

Here's a suggested way to approach it:

const result = []

data.forEach(item => {
  const target = result.find(elem => elem.category === item.groupBy);

  if (!target) {
    result.push({ category: item.groupBy, symbol: item.icon, items: [ { name: item.permission_name } ] })
  } else {
    target.items.push({ name: item.permission_name })
  }
})

This method involves creating a fresh array by filtering the original one according to your specifications.

Answer №3

If you're looking to streamline your code, one approach could be to create a function that transforms an array into an object:

const groupBy = (property, list) => {
    return list.reduce((groups, item) => {
        const propValue = item[property];
        const target = groups[propValue] ?? [];
        
        return { ...groups, [propValue]: [...target, item] };
    }, {});
};

A more concise version of the function would look like this:

const groupBy = (property, list) => list.reduce((groups, item) => ({ ...groups, [item[property]]: [...groups[item[property]] ?? [], item] }), {});

You can then use this function to group your data by a specific property:

const groupedData = groupBy('customProperty', dataArray);
// { CategoryA: [...], CategoryB: [...] }

From there, you have the option to work directly with the grouped object or further manipulate it with another utility function:

const convertToArray = (nameProperty, groupedData) => Object.entries(groupedData).map((group) => ({ [nameProperty]: group[0], items: group[1] }))

Applying this function would transform your grouped data into an array format for easier handling:

const formattedData = convertToArray('category', groupedData);

This structured approach allows you to easily filter, map, or perform other operations on the data as needed.

Answer №4

One way to accomplish this task is by extracting unique groupBy values and then looping through them to populate a new array as shown below:

let permissions= [
    {
      code: 'U00',
      permission_name: 'Read User',
      groupBy: 'User',
      icon: 'user',
    },
    {
      code: 'U01',
      permission_name: 'Create User',
      groupBy: 'User',
      icon: 'user',
    },
  
    {
      code: 'B00',
      permission_name: 'Read Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B01',
      permission_name: 'Create Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B10',
      permission_name: 'Update Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
  ];
  
  let groups = [...new Set(permissions.map(({groupBy})=>groupBy))];
  let result = [];
  for (let i = 0; i < groups.length; i++){
     let res = {};
     res.label = groups[i];
     res.icon = permissions.filter(x => x.groupBy === groups[i])[0].icon;
     res.children = [];
     let arrayOfGroup = permissions.filter(x => x.groupBy === groups[i]);
     for (let j = 0; j < arrayOfGroup.length; j ++){
        let child = {};
        child.label = arrayOfGroup[j].permission_name;
        res.children.push(child);
     }
     result.push(res);
  }
  console.log(result);
  

Answer №5

Step one - acquire the filtered essential groupBy values.

Secondly - iterate through the filtered groupBy values and generate a fresh array of objects based on your specifications.

const permissions = [
  {
    code: 'U00',
    permission_name: 'Read User',
    groupBy: 'User',
    icon: 'user',
  },
  {
    code: 'U01',
    permission_name: 'Create User',
    groupBy: 'User',
    icon: 'user',
  },

  {
    code: 'B00',
    permission_name: 'Read Batch',
    groupBy: 'Batch',
    icon: 'user',
  },
  {
    code: 'B01',
    permission_name: 'Create Batch',
    groupBy: 'Batch',
    icon: 'user',
  },
  {
    code: 'B10',
    permission_name: 'Update Batch',
    groupBy: 'Batch',
    icon: 'user',
  },
];

const groups = [ ...new Set(permissions.map(({ groupBy }) => groupBy)) ];

const result = groups.map(groupName => ({
  value: permissions.find(permission => permission.groupBy === groupName).groupBy,
  icon: permissions.find(permission => permission.icon === groupName.toLowerCase())?.icon,
  children: permissions
    .filter(permission => permission.groupBy === groupName)
    .map(n => ({ value: n.permission_name })),
}));

const output = JSON.parse(JSON.stringify(result)); // To eliminate undefined keys.

console.log(output);

Answer №6

If you want to customize the permissions Array, you can utilize Array.prototype.reduce.

let permissions = [{
      code: 'U00',
      permission_name: 'Read User',
      groupBy: 'User',
      icon: 'user',
    },
    {
      code: 'U01',
      permission_name: 'Create User',
      groupBy: 'User',
      icon: 'user',
    },
  
    {
      code: 'B00',
      permission_name: 'Read Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B01',
      permission_name: 'Create Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B10',
      permission_name: 'Update Batch',
      groupBy: 'Batch',
      icon: 'user',
    }
];
    
let results = permissions.reduce(function(accumulator, current) {
    let previousPermission = accumulator.find(function(el){
        return el.label === current.groupBy
    });
    
    if(!previousPermission){
        return accumulator.concat({
            label: current.groupBy, 
            icon: current.icon,
            children: [{
              label: current.permission_name  
            }]
        });
    } else {

        let permissionIndex = accumulator.findIndex(item => {
          return item.label === previousPermission.label;     
        });

        previousPermission = {
            ...previousPermission,
            children: [
              ...previousPermission.children,
              { label: current.permission_name }
            ]
        }
        accumulator[permissionIndex] = previousPermission;
        return accumulator;
    }
  
}, []);

console.log(results);

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 is the best way to switch between light and dark themes with the ability to locally store the current theme?

Being new to the realm of react, I have been delving into the implementation of new features using Material-UI. One particular feature I am working on involves toggling between light and dark themes, with the current theme being stored locally within the b ...

Unable to Get Basic jQuery .load Example to Function

Seeking assistance with a jQuery issue regarding loading HTML snippets into a page. When the snippet contains just HTML, it loads fine. However, when it includes a script, there seems to be an issue. Simplified code provided below for better understandin ...

There appears to be an issue with the compilation of the TypeScript "import { myVar }" syntax in a Node/CommonJS/ES5 application

In my Node application, I have a configuration file that exports some settings as an object like this: // config.js export var config = { serverPort: 8080 } Within another module, I import these settings and try to access the serverPort property: // ...

Assign a value to an Html.HiddenField without tying it to the model upon form submission

I have two classes, SubsidiaryClient and Client, that are related in a one-to-many manner as depicted below. Currently, I am utilizing MVC 5 for development. In the Create SubsidiaryClient page, to retrieve the ClientID, you need to click on the browse bu ...

Guide on finding the index of the clicked element based on its class

Is there a way to get the index of the clicked element within its list as well as in its .blue class? I have successfully obtained the index within its list, but I am struggling to figure out how to get the index within its .blue class. For instance, when ...

Using Node.js (Express) to import a JSON file from a URL

As someone new to node.js, I am attempting to retrieve a json file from a specific url (e.g. 'http://www.example.com/sample_data.json'). My objective is to fetch the file just once when the server initializes and then store it locally on the cli ...

Why does refreshing a page in AngularJS cause $rootScope values to disappear?

On my local route http://localhost:9000/#/deviceDetail/, there is a controller that handles the view. Before navigating to this view, I set certain variables on the $rootScope (such as $rootScope.dashboards). While on the view, I have access to the dashbo ...

Detecting when the Ctrl key is pressed while the mouse is hovering over an element in React

In my project, I have implemented a simple Grid that allows users to drag and drop items. The functionality I am trying to achieve is detecting when the mouse is positioned on the draggable icon and the user presses the Ctrl key. When this happens, I want ...

Refreshing a portion of the view following the submission of a post with jQuery AJAX in ASP.NET MVC

I've been developing a form for my application and I'm trying to implement AJAX submission. The data is successfully sent to the controller, but instead of refreshing the entire page, I want to display a success message on the view. Do I need to ...

"Implementing classes with AngularJS: A Step-by-Step Guide

Is there a way to dynamically add a class to the i tag after a button is clicked in AngularJS? <button type="button" title="Like" ng-click="countLikes(product.title)" class="btn btn-compare"> <i class="fa fa-thumbs-o-up"></i> </ ...

Having difficulty in setting items to a relative position in order to align them properly

I am struggling to align two div items next to each other using Bootstrap. This is for a product detail view where I want the image on the left and text on the right. It's a product detail page for an ecommerce site that I'm trying to create. May ...

Show the user a number rounded to two decimal places in JavaScript without altering its original precise value

Take for instance this decimal value: let myDecimal = 117.049701384; I need to display 117.05 to the user without altering the original precise value above. I am aiming to replicate Excel's behavior with decimals, showing a number with two decimal ...

The next.js code is functioning properly when run in development mode, but encounters issues when attempting

When using the useAddress() function in run dev, it is returning undefined undefined and then the address when console logged. However, in the run build/start, it only returns undefined. What steps should I take to resolve this issue? import { useAddres ...

Is it recommended to create model classes in React components?

Within the realms of React, the Flux architecture is utilized. According to https://reactjs.org/docs/thinking-in-react.html, React operates with two distinct models - namely, the state and props. There are recommendations provided for model management in ...

The function .change in jQuery does not function properly when attempting to fill in two select elements

Currently working on dynamically populating 2 HTML dropdowns with the help of PHP, MySQL, and jQuery. The second dropdown (area) should display options based on the selection in the first dropdown (city). Even after copying code from a previous project, I& ...

Can you explain the concept of a "subpath pattern" in NodeJS?

As I was browsing through a blog post discussing the latest features of Angular 13, one particular point caught my attention: The statement that Node.js versions older than v12.20 are no longer supported by Angular packages because they utilize the Node. ...

Ways to dynamically combine a group of objects

I'm grappling with a challenge involving an array containing two objects. After using Promise All to fetch both of these objects, I've hit a roadblock in trying to merge them dynamically. Despite experimenting with various array methods like map, ...

What is the best way to activate a JQ function with my submit button?

Is there a way to trigger a JQ function when clicking the submit button in a form? I managed to make Dreamweaver initiate an entire JS file, but not a particular function. ...

Utilizing PHP to create an interactive website

As a novice PHP developer, I took to Google in search of tutorials on creating dynamic PHP websites. What I found was that many tutorials used the $_GET variable to manipulate URLs and make them appear like this: example.com/?page=home example.com/?page= ...

Unexpected issue with controller functionality following modification to URL

Summary: I am facing an issue with my controller triggering jQuery in my AngularJS web page. The controller successfully fades out a play button and an image on the initial page, but fails to work on subsequent pages when the URL changes. I suspect that t ...