Skip to main content
marcot0005
Inspiring
Apr 14, 2022 3:25 PM UTC
Solved

Get members in multiple groups

I'm trying to think my way through a problem. What I need is, given a list of groups, I want to see a list of users that are members of all of those groups. The existing tools almost, but not quite do what I need. 

groupMembers() will give me the members of a single group, so I thought maybe if I got the members of each group and got the union() of them, that would solve my problem, but union only takes 2 lists and looping through with foreach  (I do so wish there were other types of loops!) would mean somehow getting the union of each member of the list, then unioning those results until I get down to just one list, but that sounds like a pain to code and probably not terribly efficient. 

isMemberOfGroups() is nice in that I can take a user and see if they are a member of all of a list of groups, but then I have to loop through basically all users (or at least all users in some initial group) and ultimately I am not sure how many users there could be or whether the maximum batch size of 10,000 will be enough. That doesn't seem like a whole lot of users to ultimately have as a limitation. 

Then there's getdistinctusers() which is kind of the opposite of what I want? It gives me all users across a set of groups with no duplicates, I think?

Are one of these methods the way to go? Am I missing something? 

mikes0011
mikes0011Answer
Brainy
Apr 14, 2022 6:54 PM UTC

try this out:

a!localVariables(
  
  local!allUsers: a!forEach(
    ri!groups,
    a!groupMembers(
      group: fv!item,
      direct: true(),
      memberType: "USER"
    ).data
  ),
    
  local!uniqueUsers: rule!GCO_RULE_General_distinct(  /* helper rule that unions the input array against itself */
    touniformstring(a!flatten(local!allUsers))
  ),
  
  
  a!flatten(
    a!forEach(
      local!uniqueUsers,
      
      a!localVariables(
        local!currentUser: fv!item,
        if(
          and(
            a!forEach(
              local!allUsers,
              contains(touniformstring(fv!item), local!currentUser)
            )
          ),
          local!currentUser,
          {}
        )
      )
    )
  )
)

The Expression Guru

16 replies

danny.verb
Employee
Apr 14, 2022 3:52 PM UTC

What's your use case for needing members of multiple groups? You can look into creating a temporary parent groups and adding your given groups to those parent groups and using a!groupMembers().

Another option is to use the reduce() function where you can achieve what you were looking to do with a!forEach() but with the ability to pass in each output to the next iteration.

marcot0005
Inspiring
Apr 14, 2022 4:08 PM UTC

We have user roles which are basically lists of groups a particular user needs to be a member of to do what their role requires them to do. For example, Role A might need groups 1, 2 and 3, Role B needs groups 3,4 and 5 while Role C might need groups 2,3 and 4, etc. There is potentially some overlap between roles, but not a complete overlap, and we want to be able to create/change these roles without redoing the entire security of the app.

I want to be able to get a list of people in a particular role, as defined by being a member of all the groups in a particular role. 

mikes0011
Brainy
Apr 14, 2022 4:19 PM UTC

You're talking about union() here, but I assume you really want the function intersection(), which takes two lists and returns only those elements that appear in both.  This of course could be daisychained like intersection(local!list1, intersection(local!list2, local!list3)), etc.

The Expression Guru
marcot0005
Inspiring
Apr 14, 2022 4:45 PM UTC

Ooops. Yes, that is what I meant.