Aggregation Examples
Aggregation Examples
These examples use Aggregator<T,R> and Expr to build pipelines fluently.
Imports used
import de.caluga.morphium.aggregation.Aggregator;
import de.caluga.morphium.aggregation.Expr;
Creating an Aggregator: input and output types
- Signature:
morphium.createAggregator(IncomingEntity.class, OutputType.class) - Incoming entity (
T): determines the MongoDB collection and the available fields. This type must be a Morphium@Entity; Morphium uses its mapping to resolve the backing collection and validate field references. - Output type (
R): the class instantiated for each aggregation result. Use a POJO with matching fields/getters orMapfor ad‑hoc shapes.
Fail‑fast field validation
- Morphium is designed to help you “fail fast”. When you reference a field that does not exist on the entity, Morphium throws an exception instead of silently ignoring it.
- Prefer using enums or the lambda‑based field extractor to avoid typos when building queries and matches inside aggregations. See Field Names Without String Literals.
- Grouping with sums and averages
Aggregator<Order, Map> agg = morphium.createAggregator(Order.class, Map.class);
agg.match(morphium.createQueryFor(Order.class).f("status").eq("OPEN"));
agg.group("$customerId").sum("total", "$amount").avg("avgAmount", "$amount").count("count").end();
agg.sort("-total");
List<Map> perCustomer = agg.aggregate();
- Project computed fields and unwind arrays
Aggregator<Order, Map> agg = morphium.createAggregator(Order.class, Map.class);
agg.unwind("$items");
agg.project(Expr.fields(
Expr.include("_id", 0),
Expr.field("sku", Expr.field("items.sku")),
Expr.field("revenue", Expr.multiply(Expr.field("items.price"), Expr.field("items.qty")))
));
agg.group("$sku").sum("total", "$revenue").count("sold", 1).end();
List<Map> perSku = agg.aggregate();
- Lookup (join) with another collection
Aggregator<Order, Map> agg = morphium.createAggregator(Order.class, Map.class);
agg.lookup("customers", "customerId", "_id", "customer", null, null); // simple local/foreign join
agg.unwind("$customer");
agg.project("_id", "amount", "customer.name");
List<Map> ordersWithCustomer = agg.aggregate();
- Bucketing numeric values
var boundaries = List.of(Expr.intExpr(0), Expr.intExpr(50), Expr.intExpr(100), Expr.intExpr(200));
Aggregator<Order, Map> agg = morphium.createAggregator(Order.class, Map.class);
agg.bucket(Expr.field("amount"), boundaries, null, Map.of(
"count", Expr.sum(1),
"sum", Expr.sum(Expr.field("amount"))
));
List<Map> byAmountBucket = agg.aggregate();
- Automatic bucketing
Aggregator<Order, Map> agg = morphium.createAggregator(Order.class, Map.class);
agg.bucketAuto(Expr.field("amount"), 5, Map.of("sum", Expr.sum(Expr.field("amount"))), Aggregator.BucketGranularity.POWERSOF2);
List<Map> buckets = agg.aggregate();
- Sort by count and top‑N
Aggregator<Order, Map> agg = morphium.createAggregator(Order.class, Map.class);
agg.sortByCount(Expr.field("customerId"));
agg.limit(10);
List<Map> topCustomers = agg.aggregate();
- Graph lookup (hierarchical relations)
Aggregator<Employee, Map> agg = morphium.createAggregator(Employee.class, Map.class);
agg.graphLookup(
Employee.class,
Expr.field("$reportsTo"), // start with
"_id", // connectFrom
"reportsTo", // connectTo
"hierarchy", // output array
5, // max depth
"depth", // depth field
null // optional match filter
);
List<Map> hierarchy = agg.aggregate();
- Faceted search
var base = morphium.createAggregator(Order.class, Map.class)
.match(morphium.createQueryFor(Order.class).f("status").eq("OPEN"));
var byCustomer = morphium.createAggregator(Order.class, Map.class)
.group("$customerId").sum("total", "$amount").end();
var byDay = morphium.createAggregator(Order.class, Map.class)
.project(Expr.fields(
Expr.field("day", Expr.dateToString("%Y-%m-%d", Expr.field("created"))),
Expr.include("amount")
))
.group("$day").sum("total", "$amount").end();
base.facet(Map.of("byCustomer", byCustomer, "byDay", byDay));
List<Map> facets = base.aggregate();
- Typed result projection
public class SalesSummary {
private String customerId;
private BigDecimal total;
private long count;
// getters/setters
}
Aggregator<Order, SalesSummary> agg = morphium.createAggregator(Order.class, SalesSummary.class);
agg.group("$customerId").sum("total", "$amount").count("count").end();
List<SalesSummary> result = agg.aggregate();
Tips
- Use
Exprhelpers to build expressions (e.g.,Expr.field,Expr.sum,Expr.divide,Expr.multiply) - Use
projectto rename or compute fields and limit document size - Use
limitearly in the pipeline where appropriate See also: Developer Guide