Precalculated Aggregate Columns
Sometimes you want a node to carry rolled-up data about its subtree — a total, a count, an average, a min/max — without re-running an aggregate query every time the tree is rendered. Declare the columns and the package keeps them in sync as the tree mutates.
For the examples in this section, imagine a Category model from a blog or shop. Each category has an articles integer for the number of articles directly tagged with it; the aggregates roll those counts up the tree.
use Vusys\NestedSet\Attributes\NestedSetAggregate;
#[NestedSetAggregate(column: 'articles_total', sum: 'articles')]
#[NestedSetAggregate(column: 'articles_count_all', count: true)]
#[NestedSetAggregate(column: 'articles_avg', avg: 'articles')]
#[NestedSetAggregate(column: 'articles_min', min: 'articles')]
#[NestedSetAggregate(column: 'articles_max', max: 'articles')]
class Category extends Model implements MaintainsTreeAggregates
{
use NodeTrait;
}
For a tree:
Electronics (articles = 4)
├── Computers (articles = 2)
│ ├── Laptops (articles = 8)
│ └── Desktops (articles = 3)
└── Phones (articles = 12)
…the stored aggregates on Electronics are:
$electronics->refresh()->articles_total; // 29 (4 + 2 + 8 + 3 + 12)
$electronics->articles_count_all; // 5 (self + 4 descendants)
$electronics->articles_avg; // 5.8 (29 / 5)
$electronics->articles_min; // 2
$electronics->articles_max; // 12
Every node carries its own subtree's rollup — Computers independently reports articles_total = 13 and articles_count_all = 3. Inserts, source-column updates, deletes, moves and soft-delete restores all keep the stored values current.
1. In this section
- Migration & Setup — adding aggregate columns and the model conventions that keep them honest
- Reading Values — stored vs fresh recomputation
- Declaring Aggregates — attribute and method-override forms
- Filtered Aggregates — equality, not-null, and raw SQL filters
- Collection Aggregates — distinctCount, stringAgg, jsonAgg, jsonObjectAgg
- Top-K Aggregate — the K rows with the largest ranking value across the subtree
- Listener Aggregates — PHP-computed contributions
- Variance & Stddev — statistical roll-ups, both population and sample
- Weighted Average & Boolean Rollups —
weightedAvg(value, weight),boolOr,boolAnd - Geometric & Harmonic Mean —
geometricMean/harmonicMeanwith the positivity / non-zero constraint - Median, Percentile & Quantiles — fresh-read-only quantiles via
withFreshAggregates() - Bitwise Aggregates — bitOr / bitAnd / bitXor over integer source columns
- Lazy Aggregates — defer recompute to first read with
lazy: trueand an optionalttl - Recipes — common shapes
- Maintenance — what runs when, plus integrity tooling
- Drift & Limitations — when stored values can lag and how to mitigate