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.

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);
  • 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 '17 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 '17 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

  • 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 '17 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. – Akshay Dhiman Sep 8 '17 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.