0

Here is the nested array of object i am working on:

let arrayOfElements = 
[
    {
       "username": "a",
       "attributes": 
       {
         roles:["Tenant-Hyd"],
         groups:["InspectorIP", "InspectorFT"]
       }
    },
    {
       "username": "b",
       "attributes": 
       {
         roles:["Tenant-Pune"],
      groups:["InspectorIP"]
       }
    },
    {
       "username": "c",
       "attributes": 
       {
         roles:["Tenant-Hyd"],
      groups:["InspectorIP"]
       }
    }
];

I want users if they have Tenant-hyd role and also if groups has more then one string, then the user should be spit two. so the final output should be:

arrayOfElements=[
{
    "username": "a",
     groups:"InspectorIP"
   },
   {
    "username": "a",
     groups:"InspectorFT"
   },
{
   "username": "c",

  groups:"InspectorIP"

}
];

3 Answers 3

1

I would use a combination of filter and reduce array functions here.

filter would remove all elements where attributes.roles does not include 'Tenant-Hyd'.

reduce would then flatten the groups array.

const arrayOfElements = 
[
    {
       "username": "a",
       "attributes": 
       {
         roles:["Tenant-Hyd"],
         groups:["InspectorIP", "InspectorFT"]
       }
    },
    {
       "username": "b",
       "attributes": 
       {
         roles:["Tenant-Pune"],
      groups:["InspectorIP"]
       }
    },
    {
       "username": "c",
       "attributes": 
       {
         roles:["Tenant-Hyd"],
      groups:["InspectorIP"]
       }
    }
];

const filtered = arrayOfElements.filter(x => x.attributes.roles.includes('Tenant-Hyd'));

console.log('filtered', filtered);

const flattened = filtered.reduce((arr, current) => {
  // create a new object for each group with the current username
  const groups = current.attributes.groups.map(group => ({
    username: current.username,
    groups: group
  }));
  // push the new objects into the array
  arr.push(...groups);
  // return the array to the next iteration
  return arr;
}, []);

console.log('flattened', flattened);

This demo sets up the initial array, runs the filter, and then runs the reduce. I have separated the steps out so you can see what's going on at each stage, but you could easily combine them.

const result = arrayOfElements
  .filter(x => x.attributes.roles.includes('Tenant-Hyd'))
  .reduce((arr, current) => {
    arr.push(...current.attributes.groups.map(group => ({
      username: current.username,
      groups: group
    })));
    return arr;
  }, []);

The reduce function

The reduce array function accepts a callback and an initial value. I am passing an empty array in as the initial value.

It is really a more powerful map. The source array will be iterated over, with the callback being called on each iteration. The value returned from the callback will be used as the accumulator on the next iteration.

// declare the callback
const callback = (arr, current) => {
  // arr is the initial value on the first loop
  // and whatever we return from this callback on subsequent loops

  // add our flattened items to the accumulated array
  arr.push(...current.attributes.groups.map(group => ({
    username: current.username,
    groups: group
  })));

  // return the accumulated array to the next iteration
  return arr;
};

// loop over the items in myArray, calling the callback for each item
// pass an empty array in as the accumulator
myArray.reduce(callback, []);

A simpler alternative would be this:

const arr = [];
myArray.forEach(current => {
  arr.push(...current.attributes.groups.map(group => ({
    username: current.username,
    groups: group
  })));
});

This is easier to understand, but is not as concise as using reduce.

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

5 Comments

I've added an explanation to my answer. It's hard to understand the first time you use it, but it is actually fairly simple once you get used to it.
Thanks for the explanantion Kurt, What if I wanted to create a seperate object if has two roles.I mean the flatenned object should be: [ { "username": "a", "groups": ["InspectorIP", "inspectorFT"] }, { "username": "c", "groups": "InspectorIP" } ]
That's no longer a flattened object - you would just use a straightforward map. myArray.map(item => { return { username: item.username, groups: item.groups } })
Got it Kurt, a small check, if at all i have an array of usernames ["a"] if the user exits it that, i should be adding that object into the map. I mean the final object should be : [ { "username": "c", "groups": "InspectorIP" } ] since a already exists in the array i dont want him to be added to the new list.Can you update that in code. If possible.Can that be done without for loop.
You're now changing the question after it has already been answered. Read up on array functions and search for solutions to your problem. If you are still genuinely stuck, then create a new question, and someone will be able to help you.
1

You can use the following snippet

let arrayOfElements = [{
    "username": "a",
    "attributes": {
      roles: ["Tenant-Hyd"],
      groups: ["InspectorIP", "InspectorFT"]
    }
  },
  {
    "username": "b",
    "attributes": {
      roles: ["Tenant-Pune"],
      groups: ["InspectorIP"]
    }
  },
  {
    "username": "c",
    "attributes": {
      roles: ["Tenant-Hyd"],
      groups: ["InspectorIP"]
    }
  }
];
var newa = [];
for (var i in arrayOfElements) {
  if (arrayOfElements[i].attributes.roles[0] === 'Tenant-Hyd') {
    for (var j in arrayOfElements[i].attributes.groups) {
      var newObj = {
        'username': arrayOfElements[i].username,
        'groups': arrayOfElements[i].attributes.groups[j]
      };
      newa.push(newObj);
    }
  }
}
console.log(newa);

Comments

1

You can try this code

let arrayOfElements = [{
    "username": "a",
    "attributes": {
      roles: ["Tenant-Hyd"],
      groups: ["InspectorIP", "InspectorFT"]
    }
  },
  {
    "username": "b",
    "attributes": {
      roles: ["Tenant-Pune"],
      groups: ["InspectorIP"]
    }
  },
  {
    "username": "c",
    "attributes": {
      roles: ["Tenant-Hyd"],
      groups: ["InspectorIP"]
    }
  }
];
var res = [];
arrayOfElements.forEach(d => {
  if (d.attributes.roles[0] == "Tenant-Hyd") {
    d.attributes.groups.forEach(x => {
      res.push({
        "username": d.username,
        "groups": x
      })
    })
  }
});
console.log(res);

1 Comment

Hi Milan, i can have more then one value in roles array. I guess role[0] shouldnt be there, can that issue be solved without using one more loop

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.