Aggregations
This feature is currently under development and, although not available in the current version, its preliminary documentation is provided to give you a preview of the enhancements that will be included in an upcoming update.
Context
Aggregations are a powerful feature of the public API, allowing users to compute summary statistics such as totals, averages, and counts directly on the server.
This reduces the amount of data transferred to the client, optimizing performance and ensuring efficiency in data analysis.
The API enables aggregations through grouping and aggregation functions.
By leveraging these capabilities, users can obtain pre-aggregated data in a structured manner, which is particularly useful in financial and accounting applications.
A key advantage is that users can filter the data to be aggregated using all filtering options supported by DataLoaders.
This means filters can be applied not only to the main entity but also to its parent entity (if it exists) and its child entities (if they exist).
This provides extensive flexibility in refining aggregated results, ensuring that only relevant data is considered while maintaining optimal performance.
Some Use Case Examples
-
Financial Reporting: Aggregate accounting entry lines to compute total debit and credit amounts per account over a specified period, such as monthly or quarterly balances. This enables users to track financial health and prepare accurate financial statements.
Account Code Date (Aggregated by Month) Total Debit Total Credit 601000
(Purchases of Goods)2024-03-01
1500,00
0,00
606000
(General Expenses)2024-03-01
8500,00
0,00
701000
(Product Sales)2024-03-01
0,00
22,00
707000
(Service Sales)2024-03-01
0,00
35,500
-
Journal-Level Analysis: Aggregate debit and credit amounts per journal to analyze financial flows at a higher level, ensuring compliance and better financial tracking. Since accounting entries must always balance, total debit and total credit amounts are equal.
Journal Code Date (Aggregated by Month) Total Debit Total Credit GEN
(General Journal)2024-03-01
34850,00
34850,00
SALES
(Sales Journal)2024-03-01
11200,00
11200,00
PURCHASE
(Purchase Journal)2024-03-01
1050,00
1050,00
BANK
(Bank Journal)2024-03-01
400,00
400,00
-
Sales Performance Analysis: Summarize sales document lines to calculate the total quantity sold per product or the total revenue per product category, helping businesses evaluate best-selling products and optimize inventory management.
Product Date (Aggregated by Month) Total Quantity Sold Total Sales Amount PRD001
2024-03-01
150
45,00
PRD002
2024-03-01
85
25,500
PRD003
2024-03-01
230
78,00
-
Customer Revenue Insights: Aggregate sales document headers to determine the total revenue per customer, allowing businesses to identify high-value clients and adjust marketing or sales strategies accordingly.
Customer Code Date (Aggregated by Quarter) Total Sales Amount CUST001
2024-04-01
150,00
CUST002
2024-04-01
97,500
CUST003
2024-04-01
42,600
CUST004
2024-04-01
205,300
-
Purchase Invoice Analysis: Aggregate purchase invoice amounts per supplier to track total expenses over a given period, helping businesses manage supplier relationships and control costs.
Supplier Code Date (Aggregated by Quarter) Total Purchase Amount SUPP001
2024-04-01
320,00
SUPP002
2024-04-01
210,500
-
Operational Trends: Track financial trends by aggregating accounting data over different time intervals (daily, weekly, monthly, quarterly, yearly) to monitor performance variations and detect anomalies.
Date (Aggregated Interval) Total Debit Total Credit 2024-03-30
(Daily)500
7200
2024-03-13
(Weekly)3200
45500
2024-04-01
(Monthly)12000
15200
2024-07-01
(Quarterly)35000
41000
2024-01-01
(Yearly)1450
1820
Advantages
- Efficient and Optimized Data Processing: Aggregations are computed on the server, reducing network load, minimizing database queries, and enhancing performance by returning pre-aggregated results.
- Scalability: Handles large datasets efficiently without performance degradation, ensuring seamless data retrieval even for complex queries.
- Flexible Grouping and Filtering: Users can define custom groups using account IDs, dates, or other fields while applying filters on the main entity, its parent entity (if applicable), and its child entities (if they exist) for precise data control.
- Simplified Querying and Comprehensive Analysis: A single request retrieves structured insights, eliminating complex data post-processing while enabling detailed financial and operational reporting.
Notes:
- Aggregations allow for flexible grouping using different time periods such as Day, Week, Month, Quarter, and Year.
- Aggregation is defined using two main components:
aggregateFields
: Specifies the fields to be aggregated (e.g., sum of amounts).groupFields
: Defines how the data should be grouped (e.g., by account, by date).
- The API’s aggregation capabilities enable users to perform high-level financial analysis with minimal overhead.
Example of Query
The following query demonstrates how aggregations work.
It retrieves accounting entry lines where the subAccount code starts with 6 or 7, within the specified date range, and computes total sums for creditAmount and debitAmount, grouped by subAccountId and accountingEntry.date (by Quarter).
Only the aggregation results and grouping values are returned in the response, not the detailed lines used for the calculations.
query {
accountingEntryLines(
where: {
and: [
{ accountingEntry: { date: { gte: "2021-01-01", lte: "2025-01-31" } } }
{ subAccount: {
or: [
{ code: { startsWith: "6" } },
{ code: { startsWith: "7" } }
]
}
}
]
}
) {
edges {
node {
creditAmount
debitAmount
subAccountId
accountingEntry {
date
}
}
}
totalSum(
aggregateFields: ["creditAmount", "debitAmount"],
groupFields: ["subAccountId", "accountingEntry.date|Quarter"]
) {
groupValues {
name
value
}
aggregates {
name
value
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
Addressing Aggregations with Grouping
Aggregations work by grouping data using specified fields and then applying aggregation functions to compute summary values.
-
Defining Aggregations
Aggregation fields are defined in the aggregateFields array, which lists the numeric fields that should be summed, counted, or averaged.
For example, specifying["creditAmount", "debitAmount"]
in aggregateFields with the aggregation typetotalSum
will return the total sum ofcreditAmount
anddebitAmount
for each group defined ingroupFields
.The aggregation type is specified in the query:
- Summation is defined using
totalSum
. - Averaging is defined using
average
. - Counting occurrences is defined using
count
.
- Summation is defined using
-
Grouping Data
The groupFields array specifies the fields used for grouping results.
For date-based grouping, users can define time intervals by using the
|
separator.
The resulting grouped date value will always be expressed in the formatYYYY-MM-DDT00:00:00.000Z
, where the day component is always set to01
forMonth
,Quarter
, andYear
groupings.Grouping Type Example Value Day
2024-03-30T00:00:00.000Z
Week
2024-03-30T00:00:00.000Z
Month
2024-03-01T00:00:00.000Z
Quarter
2024-07-01T00:00:00.000Z
Year
2024-01-01T00:00:00.000Z
The date grouping is one of the elements that can be defined in the
groupFields
array, meaning it can be combined with other fields for more granular aggregations.
For example, grouping by subAccountId and then by monthly period can be achieved using:groupFields: ["subAccountId", "accountingEntry.date|Month"]
This will return aggregated values grouped first by SubAccountId, and within each sub-account, by month, ensuring that financial data is structured efficiently for reporting and analysis.
-
Retrieving Aggregated Results
The API processes the request and returns aggregated data structured by the specified groups.
The aggregated results contain:groupValues
: The values of the fields used for grouping.aggregates
: The computed sums, averages, or counts for each group.
Example Response:
{ "data": { "accountingEntryLines": { "edges": [], "totalSum": [ { "groupValues": [ { "name": "subAccountId", "value": "fe5ddebf-92b5-4d6c-b56b-82efeefd95f6" }, { "name": "accountingEntry.date|Month", "value": "2024-03-01T00:00:00.000Z" } ], "aggregates": [ { "name": "creditAmount", "value": "6000" }, { "name": "debitAmount", "value": "0" } ] }, ... ] } } }
This response shows aggregated values grouped by subAccountId and by month, where each group contains the computed creditAmount and debitAmount.
Important Points and Limitations
-
Grouping Restrictions for Child Entities
While it is possible to group by fields from an entity and its main entity, it is not allowed to group by fields from child entities.
For example, grouping by
subAccountId
is valid because it belongs to the main entity. Similarly, grouping byaccountingEntry.date
is also allowed, asaccountingEntry
is the parent entity ofaccountingEntryLines
.
However, grouping bysubAccount.code
is not possible sincesubAccount
is a child entity.This limitation exists because of data loader optimizations. When executing a query, the system splits it into multiple queries to optimize performance:
- The main query retrieves the primary entity records.
- Separate follow-up queries fetch child entity data, but only for the specific child entities referenced in the query.
In the case of aggregations, child entity data has not yet been retrieved at the time of aggregation.
Since the grouping operation happens at the aggregation stage, before the child entity queries are executed, it is not possible to group by a field that has not yet been loaded. -
Exposing Fields Used in
aggregateFields
andgroupFields
It is mandatory to declare all fields used for aggregation or grouping in the
edges
node.For example, to aggregate and group:
{ ... totalSum( aggregateFields: ["creditAmount", "debitAmount"], groupFields: ["subAccountId", "accountingEntry.date|Quarter"] ) ... }
You must expose:
edges { node { creditAmount debitAmount subAccountId accountingEntry { date } } }
Conversely, it is not allowed to expose fields in
edges
that are not used in the aggregation.For example, if
totalNet
is exposed inedges
while the aggregation is:{ ... totalSum( aggregateFields: ["totalQuantity"], groupFields: ["productId", "salesOrder.documentDate|Quarter"] ) ... }
The following error will be returned:
{ "errors": [ { "message": "totalNet field is not used in the aggregation and should be removed from edges.", "extensions": { "code": "INVALID_INPUT" } } ] }
-
Pagination
Pagination works the same way as in a standard query, as explained in the pagination documentation.
Key concepts / API - PaginationHowever, it applies to aggregated results rather than the detailed queried data used for the calculations.
Example: If pagination is set to 50 using
first: 50
and the requested filter covers 2000 accounting entry lines, all 2000 lines will be used for aggregations and groupings, but only the first 50 aggregation results will be returned.query ($endCursor: String!) { salesInvoices ( first: 50 after: $endCursor where: {...} ) { edges { node { ... } } totalSum( aggregateFields: [...], groupFields: [...] ) { pageInfo { endCursor hasNextPage } } } }
- Retrieving the Full Aggregation Results:
To retrieve the full set of aggregation results, the query must be executed multiple times, assigning$endCursor
with theendCursor
value from the previous response, untilhasNextPage
isfalse
. - Pagination Limits:
The maximum number of aggregation results that can be retrieved in one request is 500 (first:500).
IfhasNextPage
istrue
, additional requests should be made usingafter: $endCursor
.
- Retrieving the Full Aggregation Results:
-
Understanding
totalCount
in AggregationsIn a standard query,
totalCount
typically returns the total number of records matching the query, regardless of the number of results returned based on the defined pagination.However, in the context of aggregations, while
totalCount
remains syntactically valid, its value is not meaningful.
This is because aggregations transform and group data, making the raw count of records irrelevant to the aggregated output.This is not a critical issue, as aggregation logic inherently requires retrieving the entire set of results to be useful.
Consequently, the total number of aggregated results can be determined by fully paginating through the aggregation query, as explained in the pagination section.