0

I need to create a Map of Sets from an SOQL query. I know that I can use something like this -

Set<Id> oppIds = new Set<Id>();
Map<Id,Set<Id>> oppIdByOppOwnerProfiles = new Map<Id,Set<Id>>();

for(Opportunity o : [SELECT Id,Opportunity.Name,OwnerId,AccountId,Owner.ProfileId
                       FROM Opportunity
                      WHERE Id IN :stage4PlusOpportunities])
            {
                if (oppIdByOppOwnerProfiles.keySet().contains(o.Owner.ProfileId)) {
                    oppIds = oppIdByOppOwnerProfiles.get(o.Owner.ProfileId);
                    oppIds.add(o.Id);
                    oppIdByOppOwnerProfiles.put(o.Owner.ProfileId,oppIds);
                } else {
                    oppIds.add(o.Id);
                    oppIdByOppOwnerProfiles.put(o.Owner.ProfileId,oppIds);
                }
            }

but I'm wondering whether it's possible to avoid checking the Map's key, retrieving the Set, updating the Set & putting the updated Set back in the map, for every result. Can I have the query group the results into a Set & key with fewer steps?

The main reason I'm asking is because GROUP BY appears to create a Map of collections from a query's results.
But it looks like I can't use that syntax because it requires every field that's retrieved to be grouped or aggregated. I am using the other fields from my query but I've removed that from my code, to keep it simple.

2 Answers 2

1

I suggest this idiomatic Apex pattern for this case because it involves a bit less code:

Set<Id> oppIds = oppIdByOppOwnerProfiles.get(o.Owner.ProfileId);
if (oppIds == null) {
    oppIds = new Set<Id>();
    oppIdByOppOwnerProfiles.put(o.Owner.ProfileId, oppIds);
}
oppIds.add(o.Id);
2
  • Thank you Keith. I'm just trying this out now, where oppIds.add(o.Id); has executed, do I then need to put that set & the profile id back in the map? In which case, would this change be an enhancement?
    – Alex S
    Sep 6, 2017 at 10:19
  • @AlexS No as Apex works by reference i.e. oppIds is a pointer into the set that is already in the map. Languages like C++ have mechanisms to make copies but most languages work by reference.
    – Keith C
    Sep 6, 2017 at 10:19
0


I have create some piece of code for you please make sure you have oppIds (opportunity Id), Please try this code.

Set<Id> oppIds = new Set<Id>();
Map<Id,Set<Id>> oppIdByOppOwnerProfiles = new Map<Id,Set<Id>>();
  for(Opportunity o : [SELECT Id, Name, OwnerId, AccountId, Owner.ProfileId FROM Opportunity WHERE Id IN :oppIds]){
   if (!oppIdByOppOwnerProfiles.containsKey(o.Owner.ProfileId)) {
       Set<Id> emptySet = new Set<Id>();
       oppIdByOppOwnerProfiles.put(o.Owner.ProfileId, emptySet);
    }
      oppIdByOppOwnerProfiles.get(o.Owner.ProfileId).add(o.Id);
}

Regards, Akshay

2
  • Hi Akshay, thanks for this. Could you please let me know what the benefits of using this approach, compared to mine & Keith's are?
    – Alex S
    Sep 5, 2017 at 10:08
  • Hi Alex, I have reduce the number of line of your code and made it easy way to do it and when I have posted this answer Keith is not putting set<Id> into the map that's why I have posted this answer. Sep 8, 2017 at 10:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .