DynamicWhere.ex
DynamicWhere.exv3.4.0·docs

Aggregator

Aggregator is the aggregation function applied inside a GroupBy. Each entry in GroupBy.AggregateBy picks one of the eight functions and a target field — and the result column is named by AggregateBy.Alias.

Values

The two columns at the end tell you whether the function accepts a field at all, and whether that field is constrained to numeric types.

ValueDescriptionSupports Field?Numeric Only?
CountCount items in the group.Optional — when no field, counts all items in the group.No
CountDistinctCount distinct values of the field.RequiredNo
SumationSum of values.RequiredYes
AverageAverage of values.RequiredYes
MinimumMinimum value.RequiredNo (except Boolean)
MaximumMaximum value.RequiredNo (except Boolean)
FirstOrDefaultSmallest value in the group — the values are ordered ascending and the first is taken, not the first row.RequiredNo
LastOrDefaultLargest value in the group — the values are ordered descending and the first is taken, not the last row.RequiredNo
Numeric-only constraints
Sumation and Average only accept numeric fields. Minimum and Maximum reject Boolean fields specifically. Violations throw a LogicException whose message is Aggregator[<agg>]IsNotSupportedForFieldType[<type>].

Validation rules

A broken rule throws LogicException. There is no error-code property — the string below is the exception message.

RuleMessage
Alias must be a plain identifier: a letter (any script) or _, then letters, digits or _. It is emitted verbatim into the generated projection, so no spaces, dots, hyphens or leading digits.AggregationMustHasValidAlias
Aliases must be unique within an AggregateBy list.AggregationAliasesMustBeUnique
An alias cannot match any GroupBy.Fields entry.AggregationAlias[<alias>]CannotBeUsedInGroupByFields
Aggregation field must be a simple type. A navigation — including a collection navigation, whose element type is what gets checked — lands here.AggregationFieldMustBeSimpleType
Aggregation field cannot be a collection. Because the element type is what gets checked, this only fires for a collection of collections — a plain collection navigation reports the row above instead.AggregationFieldCannotBeCollectionType
Sumation / Average on a non-numeric field.Aggregator[<agg>]IsNotSupportedForFieldType[<type>]
Minimum / Maximum on a Boolean field.Aggregator[<agg>]IsNotSupportedForFieldType[<type>]

JSON example

{
  "fields": ["Category"],
  "aggregateBy": [
    { "field": null,    "alias": "TotalCount",    "aggregator": "Count" },
    { "field": "Id",    "alias": "DistinctIds",   "aggregator": "CountDistinct" },
    { "field": "Price", "alias": "TotalRevenue",  "aggregator": "Sumation" },
    { "field": "Price", "alias": "AvgPrice",      "aggregator": "Average" },
    { "field": "Price", "alias": "MinPrice",      "aggregator": "Minimum" },
    { "field": "Price", "alias": "MaxPrice",      "aggregator": "Maximum" },
    { "field": "Name",  "alias": "FirstName",     "aggregator": "FirstOrDefault" },
    { "field": "Name",  "alias": "LastName",      "aggregator": "LastOrDefault" }
  ]
}

Result (illustrative single group row):

{
  "Category": "Electronics",
  "TotalCount": 15,
  "DistinctIds": 15,
  "TotalRevenue": 5249.85,
  "AvgPrice": 349.99,
  "MinPrice": 9.99,
  "MaxPrice": 1299.99,
  "FirstName": "Adapter Cable",
  "LastName": "Wireless Mouse"
}

C# usage

using DynamicWhere.ex.Enums;

var groupBy = new GroupBy
{
    Fields = new List<string> { "Category" },
    AggregateBy = new List<AggregateBy>
    {
        new AggregateBy { Field = null,    Alias = "TotalCount",   Aggregator = Aggregator.Count },
        new AggregateBy { Field = "Price", Alias = "TotalRevenue", Aggregator = Aggregator.Sumation },
        new AggregateBy { Field = "Price", Alias = "AvgPrice",     Aggregator = Aggregator.Average },
    }
};