2

First of all I am a newbie into Javascript, ES6 etc and I come from Java background. I have a complex javascript array structure (example given below), I am trying to convert this array into a map (similar to how Java has, key value pair kind of thing), key being the permission names (e.g KEY-1, KEY-2, KEY-3, KEY-4,KEY-5 with regards to the javascript array example below) while value being the comma separated values of the actual permission. I can achieve it by looping b thru the nested arrays, but loop is what I am trying to avoid here and wanted to do using map()/reduce()/filter()

Here is an example of how the map should contain the data. Since KEY-2 is present in both the arrays, they will be overridden into one (which is perfectly fine)

KEY-1 = ["Roles.Create","Roles.Edit"]
KEY-2 = ["API-Admin.Create","API-Admin.Edit","API-Admin.Read"]
KEY-3 = ["Roles.Create","Roles.Edit"]
KEY-4 = ["Users.Read"]      
KEY-5 = ["Roles.Create","Roles.Edit"]

Javascript Array

const teamArr = [
  {
    "name":"Team1",
    "accountId":"Billing",
    "teamId":"12345",
    "permissions": {
        "KEY-1": [
            "Roles.Create",
            "Roles.Edit"
        ],
        "KEY-2": [
            "API-Admin.Create",
            "API-Admin.Edit",
            "API-Admin.Read"
        ],
        "KEY-3": [
          "Roles.Create",
          "Roles.Edit"
        ]
     }
   },
   {
     "name":"Team2",
     "accountId":"Sales",
     "teamId":"6789",
     "permissions": {
         "KEY-4": [
             "Users.Read"
         ],
         "KEY-2": [
            "API-Admin.Create",
            "API-Admin.Edit",
            "API-Admin.Read"
        ],
         "KEY-5": [
           "Roles.Create",
           "Roles.Edit"
         ]
      }
   }
]

KEY-1, KEY-2,KEY-3,KEY-4, KEY-5 etc are all dynamically generated, so I CAN NOT hardcode these keys names into my code (like KEY-1, KEY-2 etc.)

I followed this post https://www.freecodecamp.org/news/15-useful-javascript-examples-of-map-reduce-and-filter-74cbbb5e0a1f/ and below is what I tried but I guess, I am struggling to properly use sort()/reduce() properly on a complex javascript array. I would prefer plain Javascript/ES6 solution (no JQuery pls).

const sorted = test.sort((a, b) => a.permissions - b.permissions);
// Using reduce:
dict = sorted.reduce(
    (dict, el, index) => (dict[el.permissions] = sorted.length - index, dict),
    {}
);

console.log(dict)

Any help here would highly be appreciated. Thanks

3 Answers 3

2

Since you don't need to worry about the other keys/values, you need to firstly create an array of all the permissions objects. Then you extract the properties from that array, keeping the arrays unique with Sets:

const teamArr = [{"name":"Team1","accountId":"Billing","teamId":"12345","permissions":{"KEY-1":["Roles.Create","Roles.Edit"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-3":["Roles.Create","Roles.Edit"]}},{"name":"Team2","accountId":"Sales","teamId":"6789","permissions":{"KEY-4":["Users.Read"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-5":["Roles.Create","Roles.Edit"]}}];
const res = teamArr.flatMap(({ permissions }) => Object.entries(permissions)).reduce((a, [k, v]) => ((a[k] = [...new Set(((a[k] = a[k] || []).push(...v), a[k]))], a)), {});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }

More verbose version:

const teamArr = [{"name":"Team1","accountId":"Billing","teamId":"12345","permissions":{"KEY-1":["Roles.Create","Roles.Edit"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-3":["Roles.Create","Roles.Edit"]}},{"name":"Team2","accountId":"Sales","teamId":"6789","permissions":{"KEY-4":["Users.Read"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-5":["Roles.Create","Roles.Edit"]}}];
const permissions = teamArr.map(({ permissions }) => permissions);
const res = permissions.flatMap(Object.entries).reduce((a, [k, v]) => {
  a[k] = a[k] || [];
  a[k].push(...v);
  a[k] = [...new Set(a[k])];
  return a;
}, {});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Jack. Your both the solutions worked like a charm. Really appreciate your help here.
No problem @JameelKhan, always glad to help. If my answer fixed your problem, please mark it as accepted.
2

You can do it with a combination of flatMap and reduce (although flatMap isn't supported on all browsers yet):

const teamArr = [{
    "name": "Team1",
    "accountId": "Billing",
    "teamId": "12345",
    "permissions": {
      "KEY-1": [
        "Roles.Create",
        "Roles.Edit"
      ],
      "KEY-2": [
        "API-Admin.Create",
        "API-Admin.Edit",
        "API-Admin.Read"
      ],
      "KEY-3": [
        "Roles.Create",
        "Roles.Edit"
      ]
    }
  },
  {
    "name": "Team2",
    "accountId": "Sales",
    "teamId": "6789",
    "permissions": {
      "KEY-4": [
        "Users.Read"
      ],
      "KEY-2": [
        "API-Admin.Create",
        "API-Admin.Edit",
        "API-Admin.Read"
      ],
      "KEY-5": [
        "Roles.Create",
        "Roles.Edit"
      ]
    }
  }
]

const result = teamArr
  .flatMap(t => Object.entries(t.permissions))
  .reduce((acc, [key, permissions]) => {
    acc[key] = acc[key] || [];
    acc[key].push(...permissions.filter(p => !acc[key].includes(p)));
    return acc;
  }, {});
  
console.log(result);

If the permissions array for a key can be very big, you can also consider using a Set next to each key in the accumulator.

1 Comment

Thanks slider, appreciate your help :-)
0
const teamArr = [
  {
    "name":"Team1",
    "accountId":"Billing",
    "teamId":"12345",
    "permissions": {
        "KEY-1": [
            "Roles.Create",
            "Roles.Edit"
        ],
        "KEY-2": [
            "API-Admin.Create",
            "API-Admin.Edit",
            "API-Admin.Read"
        ],
        "KEY-3": [
          "Roles.Create",
          "Roles.Edit"
        ]
     }
   },
   {
     "name":"Team2",
     "accountId":"Sales",
     "teamId":"6789",
     "permissions": {
         "KEY-4": [
             "Users.Read"
         ],
         "KEY-2": [
            "API-Admin.Create",
            "API-Admin.Edit",
            "API-Admin.Read"
        ],
         "KEY-5": [
           "Roles.Create",
           "Roles.Edit"
         ]
      }
   }
];



function extractPermissions(obj) {
    const perms = {};
    obj.forEach(entry => {
        if (!entry['permissions']) {
            return;
        }
        Object.keys(entry.permissions).forEach(key => {
            if (!perms[key]) {
                perms[key] = [];
            }
            entry.permissions[key].forEach(value => {
                if (!perms[key].some(val => val === value)) {
                    perms[key].push(value);
                }
            });
        });
    });
    return perms;
}
console.log(JSON.stringify(extractPermissions(teamArr), null, 2));

1 Comment

Thanks for your help René Datenschutz. The only thing is that the solution uses loops which is what I was trying to avoid, but I guess this is using plain vanilla JS/ES6, it wont have any browser version dependency. Nonetheless, appreciate your help here :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.