2

I ran across some code a while back to find fields within an AggregateResult dynamically to do some processing irregardless of what was in it.

AggregateResult results = [SELECT COUNT_DISTINCT(ParentId) FROM Account];
Set<String> aggregateColumns = new Set<String>();
String aggregateString = String.valueOf(results).removeStart('AggregateResult:').removeStart('{').removeEnd('}');

List<String> aggregateResultList = aggregateString.split(', ', 0);
for (string pair : aggregateResultList)
    if(String.isNotEmpty(pair) && pair.indexOf('=') > 0) 
    {
        List<String> keyAndValue = pair.split('=', -2);
        if (keyAndValue.size() > 0 && String.isNotEmpty(keyAndValue[0]))
            myColumns.add(keyAndValue[0]);
    }

This worked, but I was surprised he resorted to String parsing to find the value.

I thought of using JSON parsing, however, I kept running into exceptions when I tried to convert the AggregateResult to a Map of some sort. I later found out that AggregateResult's, since they are considered sObjects, are impossible to parse that way.

So, is there an easy way to find the AggregateResult fields dynamically?

  • You should post what you had tried. It's not really fair game to post questions without example code. – Adrian Larson Sep 11 '15 at 13:13
  • I could post a link to the blog that has the actual code there. I just felt weird about it. – Programmable Medley Sep 11 '15 at 13:32
  • It's kind of against the SFSE guidelines to not share what you have tried so far, so without it, I am voting this question be closed. – Adrian Larson Sep 11 '15 at 13:33
  • I went and added the code that I found from the blog, I modified it slightly, but it retains the same structure. Hope that helps. – Programmable Medley Sep 11 '15 at 13:51
7

Believe it or not, I was very, very close. JSON.deserialize may not be able to provide me a Map, but JSON.deserializeUntyped can.

Once I found out I could utilize that, I came up with the following code:

AggregateResult results = [SELECT COUNT_DISTINCT(ParentId) FROM Account];
Map<String, Object> aggregateResultMap = 
   (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(results));
aggregateResultMap.remove('attributes');

I made sure to add the line aggregateResultMap.remove('attributes') to remove any class information. From the map, I can simply call aggregateResultMap.keySet() to provide the list of fields used and so solve the "Find AggregateResult Fields Dynamically" problem.

Break-down
We can easily serialize our data by calling the JSON.serailize method. Turning it into a string. So the following code:

AggregateResult results = [SELECT COUNT_DISTINCT(ParentId) FROM Account];
System.Debug(LoggingLevel.Info, JSON.serialize(results));

Will produce a String like this:

{"attributes":{"type":"AggregateResult"},"expr0":0}

However, using `JSON.serialize won't work:

Map<String, Object> aggregateResultMap = 
   (Map<String, Object>)JSON.deserialize(JSON.serialize(results), Map<String, Object>.class);

since it throws the following Exception:

System.JSONException: Apex Type unsupported in JSON: Object

I also tried this:

Map<String, String> aggregateResultMap = 
   (Map<String, String>)JSON.deserialize(JSON.serialize(results), Map<String, String>.class);

Which threw the following Exception:

System.JSONException: Illegal value for primitive

That's why I used JSON.deserializeUntyped.

Using my answer, above:

aggregateResultMap produces:

{expr0=0}

aggregateResultMap.keySet() produces:

{expr0}

  • Could you pls show the sample o/p of aggregateResultMap.keySet() ? Just curious. – javanoob Sep 10 '15 at 21:57
  • Added it for you. – Programmable Medley Sep 10 '15 at 22:16

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.