2

I have a master-detail relation ship where I am updating the parent (lets call it Parent__c) based on its child records aggregated values (lets call the child, Child__c). The child has a relationship to another custom obj, lets call this one LookupObj__c, in it a picklist, lets call it Category__c.

I need a query that will determine the 2 most frequent LookupObj__c picklist values based on the relationship with Child__c. For this I came up with an aggregate query that groups on Parent, and on Category then order on the count desc so that I get the highest 2 per parent first on the results and where there is even results (lets say a match on category counts, then it is determined on category text comparison (so A_category would come before B_category)

So far I have something decent built where I get the results order the way I want BUT I am unsure how to get ONLY the first 2 most frequent LookupObj__c values for each parent and set that on the parent

Code:

for(AggregateResult ar: [SELECT count(id) cnt, LookupObj__r.Category__c cat, Parent__c Parent,
          Parent__r.Primary_Category__c,Parent__r.Secondary_Category__c 
         FROM Child__c
         WHERE Parent__c IN :ParentsToUpdateSet
         GROUP BY Parent__c, LookupObj__r.Category__c ,
             Parent__r.Primary_Category__c,Parent__r.Secondary_Category__c 
         order by Parent__c, count(id) desc, LookupObj__r.Category__c asc
        ]){
   system.debug('aggregateResult: ' + ar);
   Parent__c Parent = new Parent__c();
   Parent.Id = (id)ar.get('Parent');
   String cat = (String)ar.get('cat');
   //HOW DO I GET THE 2 MOST FREQUENT CATEGORIES PER TRIP ASSIGNED???
   parent.primary_category__c = 
   parent.seconday_Category__c = 

  }
1

There are several ways of doing this.

One would be to sort your GroupBy results using a for loop.

Another would be to put the results into map(s). Then take the top two results from your sorting in order to get them for the respective parents.

Since you're using a GroupBy, you could also presumably return something "like" ar[0].cnt, ar[0].Parent__r.Primary_Category__c and ar[1].cnt, ar[1].Parent__r.Primary_Category__c to get the top two for the parent with the "most" results and compare the two Parent_r's to see if they're the same. If they're not, you have the two that you're looking for that are at the top.

If they are the same, you'll need to test ar[3], ar[4], etc until you find a different Parent__r to assign as the second parent.

From the above, you'll already know the results for the highest Primary_Category__c for the first Parent__r and for the 2nd one as well. Now you need to sort the secondary category based on the what you learned determined to be the 1st and second parents.

I believe this is where you may want to put the results into two maps.

Beginning with the 1st parent, do a for loop to add the results of a loop to the map if the parent and the secondary_category__c matches parent__r that was the 1st parent and secondary_category__c isEmpty() == false. The first result you find will be the one you're looking for. Rather than putting it into a map, you could break from the for loop if you wanted to. the choice would be yours to make.

You'd repeat the same process above for the other parent__r.

1

As you need to update the same parent from different AggregateResult records, it would be better to keep a list of the parents outside of the loop. And in order to refer to them, make it a map based on Id. Then for each 2 top results, update the parent in the map. For al others, skip them until the next parent is found.

In code it would mean something like this (not tested so forgive me any typos etc):

Map<Id,Parent__c> parentIdToParent = new Map<Id,Parent__c>();
Id currentParent;

for(AggregateResult ar: [SELECT count(id) cnt, LookupObj__r.Category__c cat, Parent__c Parent,
          Parent__r.Primary_Category__c,Parent__r.Secondary_Category__c 
         FROM Child__c
         WHERE Parent__c IN :ParentsToUpdateSet
         GROUP BY Parent__c, LookupObj__r.Category__c ,
             Parent__r.Primary_Category__c,Parent__r.Secondary_Category__c 
         ORDER BY Parent__c, count(id) desc, LookupObj__r.Category__c asc
        ])
{
    // assigning the aggregateresults to a variable for readability
    Id thisParentId = (Id)ar.get('Parent');
    String category = (String)ar.get('cat');
    if(thisParentId != currentParent){
        // top result, add as primary. Since this is the first, create a new entry in the map
        parentIdToParent.put(thisParentId,new Parent__c(Id=thisParentId,Primary_Category__c=category));
        currentParentId = thisParentId;
    } else {
        // next result. Add only if secondary. Get the entry from the map and update it
        if(parentIdToParent.get(thisParentId).secondary_category__c == null){
            parentIdToParent.get(thisParentId).secondary_category__c = category;
        } else {
            // not relevant. go to next result
            continue;
        }
    }
}
// now update the parents
update parentIdToParent.values();

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.