2

I am writing some Google Apps Script to get each Google Group and list it's members then output it to a Google Sheet. Currently, I am grabbing each group and email address and pushing it to the memberArr, however I then want to 'merge' the relevant information.

So if for example, I have X Groups and Group 1 has 4 members (Foo, Bar, Baz and Quux) - Currently, it will output as

[ [ 'Group 1', 'Foo' ],
  [ 'Group 1', 'Bar' ],
  [ 'Group 1', 'Baz' ],
  [ 'Group 1', 'Quux' ] ]

But I want to have it output as [Group 1, Foo, Bar, Baz, Quux].
That is to say, merge the contents of the memberArr where there is a common Group

Here is my code so far:

function getAllGroupsTEST() {
  const groupArr = [];
  let gPageToken;
  let gPage;

  do {
    gPage = AdminDirectory.Groups.list({
      customer: "my_customer",
      maxResults: 100,
      gPageToken
    });
    const groups = gPage.groups;

    if (groups) {
      groups.forEach(({email}) => {
        const groupEmail = email;
        groupArr.push(groupEmail);
      });
    }

    gPageToken = gPage.nextPageToken;
  } while (gPageToken);

  console.log(`LOGGING GROUPS:\n\n${groupArr}`);
  const memberArr = [];
  let mPageToken;
  let mPage;

  groupArr.forEach(group => {
    mPage = AdminDirectory.Members.list(group,{
      customer: "my_customer",
      maxResults: 500,
      mPageToken
    })
    const members = mPage.members;
    if (members) {
      // console.log(`LOGGING ${members.length} MEMBERS FOR ${group}\n\n${members}`)
      members.forEach(member => {
        // console.log(`MEMBER: ${member.email} IS IN GROUP ${group}`)
        memberArr.push([group, member.email])
      })
    }
  })
  // console.log(`COUNTED ${groupArr.length} GROUPS`)
  // console.log(memberArr)
}

Any help would be greatly appreciated!

Edit: Updated to show the memberArr as is rather than in a table format.

SL8t7
  • 617
  • 2
  • 9
  • 27
  • Can you show us what the arrays look like rather than the table? – mstephen19 Mar 31 '22 at 11:15
  • @mstephen19 - Here are the schemas if that helps: [Member](https://developers.google.com/admin-sdk/directory/reference/rest/v1/members#Member) and [Group](https://developers.google.com/admin-sdk/directory/reference/rest/v1/groups#Group) – Yogi Mar 31 '22 at 11:24
  • 1
    Edited to show the memberArr as an array rather than a table – SL8t7 Mar 31 '22 at 11:32
  • Here is a related question that shows how to do it [Most efficient method to groupby on an array of objects](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects) However, I think it would be less complex to change your existing code to build the structure you want on first pass rather than add another step to group by group. – Yogi Mar 31 '22 at 11:44

3 Answers3

3

I'd propose to convert the array in the object and then back to the array this way:

var arr = [
    ['group1','a'],
    ['group1','b'],
    ['group2','c'],
    ['group2','d'],
    ['group3','e']
]

var obj = {}
for (var a of arr) {
    try { obj[a[0]].push(a[1]) }
    catch(e) { obj[a[0]] = [a[1]] }
}
console.log(obj);

var new_arr = [];
for (var group in obj) {
    new_arr.push([group, ...obj[group]])
}
console.log(new_arr);

Output:

[ [ 'group1', 'a', 'b' ], [ 'group2', 'c', 'd' ], [ 'group3', 'e' ] ]
Yuri Khristich
  • 13,448
  • 2
  • 8
  • 23
2

I like @YuriKhristich solution. However, I still want to post this code showing how you could make a few minor changes to your existing code to build your required data structure.

We start by initializing a list with the group email. Next we append all the member emails to the list. And finally we push the completed list to memberArr. The advantage is that this builds the required data format while the data is read rather than trying to rework it afterward.

    let list = [group];  // <-- ADD

    if (members) {
        members.forEach(member => {
          
          // memberArr.push([group, member.email])  <-- REMOVE
          
          list.push(member.email);   // <-- ADD
          
        })
        memberArr.push(list);  // <-- ADD
     }
  })

// Simulated Google Groups data

var gPage = {
  groups: [
    {id: 1, name: "Group 1", email: "group1@emal.com" },
    {id: 2, name: "Group 2", email: "group2@emal.com" },
    {id: 3, name: "Group 3", email: "group3@emal.com" }
  ]
};

var mPage = { 
  members: [
    {id: 1, role: "admin", email: "member1@email.com" },
    {id: 2, role: "admin", email: "member2@email.com" },
    {id: 3, role: "admin", email: "member3@email.com" },
    {id: 4, role: "admin", email: "member4@email.com" },
    {id: 5, role: "admin", email: "member5@email.com" }
  ]
};


function getAllGroupsTEST() {

  const groupArr = [];
  let gPageToken;
  //let gPage;

  do {
    
    /* useing fake data
    gPage = AdminDirectory.Groups.list({
      customer: "my_customer",
      maxResults: 100,
      gPageToken
    });
    */
    
    const groups = gPage.groups;

    if (groups) {
      groups.forEach(({email}) => {
        const groupEmail = email;
        groupArr.push(groupEmail);
      });
    }

    gPageToken = gPage.nextPageToken;

  } while (gPageToken);



  const memberArr = [];
  let mPageToken;
  //let mPage;

  groupArr.forEach(group => {
  
     /* using fake data
      mPage = AdminDirectory.Members.list(group,{
        customer: "my_customer",
        maxResults: 500,
        mPageToken
      })
    */


    const members = mPage.members;

    let list = [group];

    if (members) {
        members.forEach(member => {
          
          // memberArr.push([group, member.email])
          
          list.push(member.email);
          
        })
        
        memberArr.push(list);
        
     }
    
  })

  return memberArr;

}

console.log( getAllGroupsTEST() );
Yogi
  • 6,241
  • 3
  • 24
  • 30
1

You can implement this easy function for every group you want to filter

Take into account that this will eliminate every duplicate of the array.

const dataToFiler = [['Group 1', 'Foo'],
['Group 1', 'Bar'],
['Group 1', 'Baz'],
['Group 1', 'Quux']]

const filterRD = (arr) => {
  return [...new Set(arr.flat())]
}

console.log(filterRD(dataToFiler))
Documentation
Emel
  • 2,283
  • 1
  • 7
  • 18
  • I like this answer, but unfortunately it fails when the data has more than 1 group. Maybe you can rework it as it seems close. – Yogi Mar 31 '22 at 12:35
  • And what is the form of the data? `[[Group1, xxxx],[Group2,xxxx]` or `[[[Group1,xxxx],[Group1,xxxx]],[[Group2,xxxxx],...]` or `[[[Group1,xxxx],[Group1,xxxx]],[[Group2,xxxxx],...]`. – Emel Mar 31 '22 at 12:45
  • In the code, all values are appended to memberArr. So I think the data is [[group1,xxxx],[group1,xxxx],[group2, xxxx],[group2,xxxx],[group3,xxxx], .... – Yogi Mar 31 '22 at 13:03