function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
BroncoBoyBroncoBoy 

Building a map of lists, error accessing subquery field values. Error: Invalid aggregate relationship

Ulitmate Goal:
Create a map of lists (contactIdsToOpportunities)  which maps a contact id to the list of opportunities that contact is associated with within the OpportunityContactRole object - all based on a limited # of contact id's, only opportunities within the last 30 days.

As I'm trying to access the subquery field values to build my map of lists, its generating the following error: 
Invalid aggregate relationship OpportunityContactRole for Opportunity


I'm trying to use this approach:  http://www.infallibletechie.com/2012/04/how-to-get-subquery-field-value-using.html

I'm grateful for any help, so thanks in advance!
-Bronco

CODE:
set <Id> evtsContactIds = new set <Id>{'0035000000yim1c’,’0035000000cin2f’};//insert contacts id's here
map <Id, List <Opportunity>> contactIdsToOpportunities = new Map <Id, List <Opportunity>>();

for (Opportunity o: [SELECT Id, CloseDate, Description, Name, (SELECT ContactId FROM OpportunityContactRoles WHERE ContactId IN: evtsContactIds) FROM Opportunity WHERE CloseDate >= LAST_N_DAYS: 30 AND Id IN(SELECT OpportunityId FROM OpportunityContactRole WHERE ContactId IN: evtsContactIds) ORDER BY CloseDate DESC])
{
    List < OpportunityContactRole > opptys = new List < OpportunityContactRole > ();
    opptys = o.getSObjects('OpportunityContactRole'); //very rarely used method, but this gets the records from the subquery, 
    Id oppContId;
    for (OpportunityContactRole opt: opptys)
    {
        oppContId = opt.ContactId;

        if (contactIdsToOpportunities.containsKey(oppContId))
        {
            List < Opportunity > contactsOpportunities = contactIdsToOpportunities.get(oppContId);
            if (contactsOpportunities.size() <= 3) //this is what determines that the code will only return the latest 3 opportunities
            {
                contactsOpportunities.add(o);
                contactIdsToOpportunities.put(oppContId, contactsOpportunities);
            }
        }
        else
        {
            contactIdsToOpportunities.put(oppContId, new List <Opportunity>{o});
        }
    }
}
Best Answer chosen by BroncoBoy
BroncoBoyBroncoBoy
I was able to solve this by stumbling on an article (not sure whyI couldn't find this article yesterday):
https://developer.salesforce.com/forums/?id=906F0000000AZyTIAW

Thanks again for trying to help!

 The problem was solved by casting soject to the child type.

Here's the final code, corrections in bold - hopefully this can help someone:

set <Id> evtsContactIds = new set <Id>{'0035000000yim1c’,’0035000000cin2f’};//insert contacts id's here
map <Id, List <Opportunity>> contactIdsToOpportunities = new Map <Id, List <Opportunity>>();

for (Opportunity o: [SELECT Id, CloseDate, Description, Name, (SELECT ContactId FROM OpportunityContactRoles WHERE ContactId IN: evtsContactIds) FROM Opportunity WHERE CloseDate >= LAST_N_DAYS: 30 AND Id IN(SELECT OpportunityId FROM OpportunityContactRole WHERE ContactId IN: evtsContactIds) ORDER BY CloseDate DESC])
{
    List < OpportunityContactRole > opptys = new List < OpportunityContactRole > ();
    opptys = o.getSObjects('OpportunityContactRole'); //very rarely used method, but this gets the records from the subquery,
 
    
    //Also, I had to use plural form of OpportunityContactRole - OpportunityContactRoles

    List<SObject> sObjectOpptys = o.getsobjects('OpportunityContactRoles');
    List<OpportunityContactRole> opptys = (List<OpportunityContactRole>)sObjectOpptys;

    Id oppContId;
    for (OpportunityContactRole opt: opptys)
    {
        oppContId = opt.ContactId;

        if (contactIdsToOpportunities.containsKey(oppContId))
        {
            List < Opportunity > contactsOpportunities = contactIdsToOpportunities.get(oppContId);
            if (contactsOpportunities.size() <= 3) //this is what determines that the code will only return the latest 3 opportunities
            {
                contactsOpportunities.add(o);
                contactIdsToOpportunities.put(oppContId, contactsOpportunities);
            }
        }
        else
        {
            contactIdsToOpportunities.put(oppContId, new List <Opportunity>{o});
        }
    }
}

All Answers

BroncoBoyBroncoBoy
I should mention that opptys = o.getSObjects('OpportunityContactRole');  is the line of code generating the error.

​-Bronco
Chandra Sekhar CH N VChandra Sekhar CH N V
Is there a separate definition of getSObjects() method? Can you please post it.
BroncoBoyBroncoBoy
getSObjects is not a method I created.  It is available to the sObject class and is elaborated on here:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_sobject.htm#apex_System_SObject_getSObjects
BroncoBoyBroncoBoy
I was able to solve this by stumbling on an article (not sure whyI couldn't find this article yesterday):
https://developer.salesforce.com/forums/?id=906F0000000AZyTIAW

Thanks again for trying to help!

 The problem was solved by casting soject to the child type.

Here's the final code, corrections in bold - hopefully this can help someone:

set <Id> evtsContactIds = new set <Id>{'0035000000yim1c’,’0035000000cin2f’};//insert contacts id's here
map <Id, List <Opportunity>> contactIdsToOpportunities = new Map <Id, List <Opportunity>>();

for (Opportunity o: [SELECT Id, CloseDate, Description, Name, (SELECT ContactId FROM OpportunityContactRoles WHERE ContactId IN: evtsContactIds) FROM Opportunity WHERE CloseDate >= LAST_N_DAYS: 30 AND Id IN(SELECT OpportunityId FROM OpportunityContactRole WHERE ContactId IN: evtsContactIds) ORDER BY CloseDate DESC])
{
    List < OpportunityContactRole > opptys = new List < OpportunityContactRole > ();
    opptys = o.getSObjects('OpportunityContactRole'); //very rarely used method, but this gets the records from the subquery,
 
    
    //Also, I had to use plural form of OpportunityContactRole - OpportunityContactRoles

    List<SObject> sObjectOpptys = o.getsobjects('OpportunityContactRoles');
    List<OpportunityContactRole> opptys = (List<OpportunityContactRole>)sObjectOpptys;

    Id oppContId;
    for (OpportunityContactRole opt: opptys)
    {
        oppContId = opt.ContactId;

        if (contactIdsToOpportunities.containsKey(oppContId))
        {
            List < Opportunity > contactsOpportunities = contactIdsToOpportunities.get(oppContId);
            if (contactsOpportunities.size() <= 3) //this is what determines that the code will only return the latest 3 opportunities
            {
                contactsOpportunities.add(o);
                contactIdsToOpportunities.put(oppContId, contactsOpportunities);
            }
        }
        else
        {
            contactIdsToOpportunities.put(oppContId, new List <Opportunity>{o});
        }
    }
}
This was selected as the best answer