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 HasNestedSet
{
    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.

In this section