0

I tried to make use of maps but still getting CPU time error.

Code:

 //@AuraEnabled
public static Map<String, Integer> getDateRangeMap()
{
    Map<String, Integer> mapToReturn = new Map<String, Integer>();
    Integer mnth = System.Today().MOnth();
    Integer yr = System.Today().Year();
    Integer previousmonth = Date.today().addMonths(-1).month();
     Integer nextmonth = Date.today().addMonths(1).month();
            List<customobj__c> myCalls = new List<customobj__c>([SELECT Id,  Name, Date__c FROM customobj__c where owner.Id =: UserInfo.getUserId() and CALENDAR_YEAR(Date__c)= :yr and (CALENDAR_MONTH(Date__c)= :previousmonth or CALENDAR_MONTH(Date__c)= :nextmonth or CALENDAR_MONTH(Date__c)= :mnth ]);
   .
    List<Opportunity> lstOpp = new List<Opportunity>([select Id, Name, closeDate from Opportunity where closeDate != NULL AND StageName!= 'Won - Closed' AND StageName!= 'Closed - No Win' AND ownerId =: UserInfo.getUserId()and CALENDAR_MONTH(closeDate)= :mnth and CALENDAR_YEAR(closeDate)= :yr]); 
    List<Event> lstEvent = new List<Event>([SELECT AccountId,EndDateTime,Id,StartDateTime,Subject FROM Event  where ownerId =: UserInfo.getUserId() and CALENDAR_MONTH(StartDateTime)= :mnth and CALENDAR_YEAR(StartDateTime)= :yr]);

    //processing the data for the map. 
    //Logic - Iterate through all dates{Iterate over list--Transform the date with the string--iterate for its count}
    for(customobj__c objCR : myCalls){
        mapToReturn.put(objCR.Date__c.format(), 0);
        //system.debug('mapToReturn CR'+mapToReturn);
    }

    for(Opportunity oOpp : lstOpp){
        mapToReturn.put(oOpp.closeDate.format() , 0);
         system.debug('mapToReturn opp'+mapToReturn);
    }

    for(Event oEvt : lstEvent)
    {
        if(oEvt.StartDateTime != NULL)
        {
            mapToReturn.put(oEvt.StartDateTime.date().format() , 0);  
             system.debug('mapToReturn Evt SD'+mapToReturn);
        }
        if(oEvt.EndDateTime != NULL)
        {
            mapToReturn.put(oEvt.EndDateTime.date().format() , 0);
             system.debug('mapToReturn Evt ED'+mapToReturn);
        }

        //we got all unique dates now. Now, we'll iterate through all the obj loops to get count
        for(String oStr : mapToReturn.keySet())
        {
            //convert string into date again.
            system.debug('oStr'+oStr);
            Date d = Date.parse(oStr);
            Integer count = mapToReturn.get(oStr);
            system.debug('!!!!!count'+count);
            for(customobj__c objCR : myCalls)
            {
                if(objCR.Date__c != NULL ){
                    if( d.isSameDay(objCR.Date__c) ){
                        count = count + 1;
                    }    
                }
            }

            for(Opportunity oOpp : lstOpp){
                if(oOpp.CloseDate != NULL ){
                    if(d.isSameDay(oOpp.CloseDate) ){
                        count = count + 1;
                    }
                }
            }

            for(Event oEvtt : lstEvent){
                if(oEvtt.StartDateTime != NULL){

                    if(oEvtt.EndDateTime == NULL){
                        if( d.isSameDay(oEvtt.StartDateTime.date())){
                            count = count + 1;
                        }
                    }else{
                        if(oEvtt.StartDateTime.date().daysBetween(d) >=0 && oEvtt.EndDateTime.date().daysBetween(d) <= 0 ){
                            count = count + 1;
                        }
                    }
                }
            }

          mapToReturn.put(oStr, count);


        }

    }
    System.debug(mapToReturn);
    return mapToReturn;
}

Here is the updated logic:

 Map<Date, Integer> myMap = new Map<Date, Integer>();  
  Integer mnth = System.Today().MOnth();
  Integer yr = System.Today().Year();
  Integer previousmonth = Date.today().addMonths(-1).month();
  Integer nextmonth = Date.today().addMonths(1).month();

  for(AggregateResult aggregate3:[SELECT day_only(StartDateTime), count(Id) records1   FROM Event WHERE owner.Id =: UserInfo.getUserId() and CALENDAR_YEAR(StartDateTime)= :yr and (CALENDAR_MONTH(StartDateTime)= :previousmonth or CALENDAR_MONTH(StartDateTime)= :nextmonth or CALENDAR_MONTH(StartDateTime)= :mnth )  GROUP BY day_only(StartDateTime)]){
    Date key = (Date)aggregate3.get('expr0');
    Integer value = (Integer)aggregate3.get('records1');
    myMap.put(key,value);
 }

    for(AggregateResult aggregate :[SELECT Date__c, count(Id) records  FROM myobject__c WHERE owner.Id =: UserInfo.getUserId() and CALENDAR_YEAR(Date__c)= :yr and (CALENDAR_MONTH(Date__c)= :previousmonth or CALENDAR_MONTH(Date__c)= :nextmonth or CALENDAR_MONTH(Date__c)= :mnth )  GROUP BY Date__c]){
 Date key = (Date)aggregate.get('Date__c');
 Integer value = (Integer)aggregate.get('records');
 myMap.get(key) += value;
}

for(AggregateResult aggregate2:[SELECT closeDate, count(Id)  FROM Opportunity WHERE owner.Id =: UserInfo.getUserId() and CALENDAR_YEAR(closeDate)= :yr and (CALENDAR_MONTH(closeDate)= :previousmonth or CALENDAR_MONTH(closeDate)= :nextmonth or CALENDAR_MONTH(closeDate)= :mnth )  GROUP BY closeDate]){
 Date key = (Date)aggregate2.get('closeDate');
 Integer value = (Integer)aggregate2.get('expr0');
 myMap.get(key) += value;

}
  • Consider moving this to javascript if you're getting CPU errors. Use the controller to return the record lists back to the component and let the component handle the rest. – gNerb Oct 16 '17 at 15:14
  • Please note that creating duplicate accounts to circumvent a question ban is likely to get you into further trouble. I suggest you request to merge your account with this likely duplicate rather than getting caught and further punished. – Adrian Larson Oct 16 '17 at 16:15
  • 2
    debug statements consume cpu time – cropredy Oct 16 '17 at 18:18
2

You're doing several things which are inefficient:

  • Don't instantiate a new list with query results. A query already returns a list.

    Instead of:

    List<MyObject__c> records = new List<MyObject__c>([/*query*/]);
    

    Just use:

    List<MyObject__c> records = [/*query*/];
    
  • Casting from date to string and then back to date is just wasting time. You get the date values from your records, then save the value as a string, but when you retrieve it you actually need the date. Save yourself the data-type-roundtrip.

    Instead of:

    Map<String, Integer> myMap = new Map<String, Integer>();
    // ...
    myMap.put(someDate.format(), 0);
    // ...
    for (String key : myMap.keySet())
    {
        Date dateKey = Date.parse(key);
        // converting back and forth like this is inefficient
    }
    

    Use:

    Map<Date, Integer> myMap = new Map<Date, Integer>();
    // ...
    myMap.put(someDate, 0);
    // ...
    for (Date dateKey : myMap.keySet())
    {
        // now you already have the date value
    }
    
  • Aggregate queries can do a lot of the computing for you without counting against CPU Time. Something like:

    for (AggregateResult aggregate : [
        SELECT MyDateField__c, count(Id) records
        FROM MyObject
        WHERE ...
        GROUP BY MyDateField__c
    ]){
        Date key = (Date)aggregate.get('MyDateField__c');
        Integer value = (Integer)aggregate.get('records');
        myMap.get(key) += value;
    }
    
  • You don't need daysBetween to do comparison, nor to even to get the Date instance from the Datetime.

    Instead of:

    if (startDatetime.date().daysBetween(myDate) >= 0 && endDatetime.date().daysBetween(myDate) <= 0)
    

    Just use:

    if (startDatetime <= myDate && endDatetime >= myDate)
    

As noted in the comments:

  • Remove all your debug statements. They consume CPU Time.
  • Make sure you are not logging at a too-fine level of granularity either. In fact, if your user has a trace flag, set all debug levels to the lowest value.
  • Hi Adrian, Thanks for the suggestions. I have updated my logic by using aggregated result but when I am trying to assign integer value to the map by getting the key, I am hitting error saying 'Expression cannot be assigned' when using myMap.get(key) += value; Anyway we could add the count value to the Map value of specific key? – consultantsfdc Oct 16 '17 at 19:58
  • Please update your question with what you tried... – Adrian Larson Oct 16 '17 at 19:59

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.