I want to apply a custom aggregate function after grouping by a property. From the documentation it seems like the aggregate functions usable are limited to: count, average, max, min, sum, cardinality.
Hi @sstanisor, it depends on which type of calculation you’re trying to achieve. In the past, when faced with a similar situation I’ve used the defined buckets from the groupBy statement to create a map and then build the custom logic from there. This can probably be streamlined a bit, but leaving it all as separate steps for code clarity:
import { Double, Function, FunctionsMap } from "@foundry/functions-api";
import { Objects, YourObjectType} from "@foundry/ontology-api";
export class CustomAggregation {
@Function()
public async customGroupByFunction(): Promise<FunctionsMap<string, Double>> {
// Perform a groupBy operation on the object set
const result = await Objects.search()
.yourObjectType() // Replace with your actual object type
.groupBy(obj => obj.YourGroupingProperty.topValues()) // Replace with the property you want to group by
.sum(obj => obj.YourAggregationProperty); // Replace with the property you want to aggregate
// Apply your custom function to the result
const customResult = new FunctionsMap<string, Double>();
result.buckets.forEach(bucket => {
customResult.set(bucket.key, bucket.value * 2) // Example: multiply each value by 2
});
return customResult;
}
}
The example here is quite straightforward as it’s just multiplying the value by 2, but you can use the same type of flow [Grouping → Initial Aggregation → Map → Call map values to do custom logic → output]
Hi @sboari , thank you for your reply. I am not sure your method works. Imagine for example you are trying to implement argmin as the aggregate function.
When accessing the buckets, you get access to the keys and the aggregated value (not the list of values the aggregate was computed on).
For argmin, what I ended up doing is something similar to what you are proposing, where you first compute the min and then use a filter.
Indeed, for the argmin example, you wouldn’t have access to all values as the keys would be referring to the aggregated buckets. The example above assumed you wanted to apply custom logic after doing the groupby.
Note that if you need additional control over the granularity of your groupby, you can change the .topValues() to .exactMatch() and include the maximum number of buckets you use via something like: