1

I am trying to return the email and id from a report inside of an apex flow using the following code. The flow sends 1 report id to the apex class.

I keep getting back "Error Occurred: The number of results does not match the number of interviews that were executed in a single bulk execution request". I've tried every suggestion I can find but I am stumped.

public class ReportDataExtractor {
    @InvocableMethod(label='Extract Email and ID' description='Extracts Email and ID from a report')
    public static List<ReportResultWrapper> extractData(List<ReportRequest> requestList) {
        List<ReportResultWrapper> resultList = new List<ReportResultWrapper>();

        if (requestList != null && !requestList.isEmpty()) {
            for (ReportRequest request : requestList) {
                String reportId = request.reportId; // Use the provided reportId
                // Run a report synchronously
                System.debug('reportid'+reportId);
                Reports.reportResults results = Reports.ReportManager.runReport(reportId, true);
                System.debug('reportresults'+results);
                
                // Get the first down-grouping in the report
                Reports.Dimension dim = results.getGroupingsDown();
                Reports.GroupingValue groupingVal = dim.getGroupings()[0];

                // Construct a fact map key, using the grouping key value
                String factMapKey = groupingVal.getKey() + '!T';

                // Get the fact map from the report results
                Reports.ReportFactWithDetails factDetails =
                    (Reports.ReportFactWithDetails)results.getFactMap().get(factMapKey);

                // Get the first summary amount from the fact map
                Reports.SummaryValue sumVal = factDetails.getAggregates()[0];
                System.debug('Summary Value: ' + sumVal.getLabel());

                for (Reports.ReportDetailRow detailRow : factDetails.getRows()) {
                    ReportResultWrapper result = new ReportResultWrapper();
                    result.id = detailRow.getDataCells()[0].getLabel();
                    result.email = detailRow.getDataCells()[1].getLabel(); 
                    resultList.add(result);
                }

              
            }
        }
        System.debug('resultList: '+resultList);
        return resultList;
    }

    public class ReportRequest {
        @InvocableVariable(label='Report ID' description='ID of the report to query' required=true)
        public String reportId;

        @InvocableVariable(label='Filter Condition' description='SOQL filter condition for the report data')
        public String filterCondition; // No longer required
    }

    public class ReportResultWrapper {
        @InvocableVariable(label='Email' description='Extracted Email')
        public String email;

        @InvocableVariable(label='ID' description='Extracted ID')
        public String id;

        @InvocableVariable(label='Results' description='Report Results')
        public List resultList;

    
    }
}

1 Answer 1

2

Apex invocable methods are bulkified; you can read more on InvocableMethod. This is because flows themselves are bulkified. For each input, there must be exactly one output, because each output will go to the flow interview that requested it. For example, in a DML where 5 record-triggered flows call the same Apex action at the same time, there will be five input elements, and there must be five output elements. You'll need to accommodate for this bulkification behavior. You should be able to fix this by wrapping the top-level element into another list:

    @InvocableMethod(label='Extract Email and ID' description='Extracts Email and ID from a report')
    // Here, return type changes to a two-dimensional list
    public static List<List<ReportResultWrapper>> extractData(List<ReportRequest> requestList) {
        // All results
        List<List<ReportResultWrapper>> resultList = new List<List<ReportResultWrapper>>();

        for (ReportRequest request : requestList) {
            // For each request, we make a list to add to resultList
            List<ReportResultWrapper> subResult = new List<ReportResultWrapper>();
            String reportId = request.reportId; // Use the provided reportId
            // Run a report synchronously
            System.debug('reportid'+reportId);
            Reports.reportResults results = Reports.ReportManager.runReport(reportId, true);
            System.debug('reportresults'+results);
            
            // Get the first down-grouping in the report
            Reports.Dimension dim = results.getGroupingsDown();
            Reports.GroupingValue groupingVal = dim.getGroupings()[0];

            // Construct a fact map key, using the grouping key value
            String factMapKey = groupingVal.getKey() + '!T';

            // Get the fact map from the report results
            Reports.ReportFactWithDetails factDetails =
                (Reports.ReportFactWithDetails)results.getFactMap().get(factMapKey);

            // Get the first summary amount from the fact map
            Reports.SummaryValue sumVal = factDetails.getAggregates()[0];
            System.debug('Summary Value: ' + sumVal.getLabel());

            for (Reports.ReportDetailRow detailRow : factDetails.getRows()) {
                ReportResultWrapper result = new ReportResultWrapper();
                result.id = detailRow.getDataCells()[0].getLabel();
                result.email = detailRow.getDataCells()[1].getLabel(); 
                subResult.add(result);
            }
            resultList.add(subResult);
        }
        System.debug('resultList: '+resultList);
        return resultList;
    }

You might want to just rewrite the result wrapper to contain a list inside of itself, as in:

public class ReportResult {
  @InvocableVariable(label='Results') public ReportResultWrapper[] results = new ReportResultWrapper[0];
}

and restructure everything to match the new design.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .