Aggregation Examples¶
These examples use Aggregator<T,R>
and Expr
to build pipelines fluently.
Imports used
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 orMap
for 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.
1) 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();
2) 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();
3) 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();
4) 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();
5) 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();
6) 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();
7) 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();
8) 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();
9) 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 Expr
helpers to build expressions (e.g., Expr.field
, Expr.sum
, Expr.divide
, Expr.multiply
)
- Use project
to rename or compute fields and limit document size
- Use limit
early in the pipeline where appropriate
See also: Developer Guide