One to Many and Its Inverse

The parent declares hasMany(Order::class) and the child belongsTo(Customer::class); the categories tree declares both on one class. $ana->orders loads a collection, $ana->orders() counts in SQL. Relationships also filter the parent query: has() keeps parents with related rows (optionally a count), doesntHave() the rest, and whereHas() adds conditions:

Walking a relationship both ways and filtering parents by itSQL
use App\Models\{Category, Customer};
echo Category::find(1)->children->pluck('name')->join(', '), "\n";
echo Customer::has('orders', '>=', 2)->pluck('name')->join(', '), "\n";
$paid = Customer::whereHas('orders', fn ($q) => $q->where('status', 'paid'));
echo $paid->pluck('name')->join(', '), "\n", $paid->toRawSql(), "\n";
Output
Programming, Databases, Design
Ana Souza, Ben Carter, Chen Wei
Chen Wei, Farah Rahman, Ben Carter
select * from `customers` where exists (select * from `orders` where `customers`.`id` =
    `orders`.`customer_id` and `status` = 'paid')

whereHas() is a correlated EXISTS (Correlated Subqueries), fast only with an index on orders.customer_id. whereRelation('orders', 'status', 'paid') is its one-condition shorthand; withCount() and withSum() add totals as columns (Counting Relations). Whole category subtrees need a recursive CTE (Recursive CTEs) or laravel-adjacency-list 1,575 (https://github.com/staudenmeir/laravel-adjacency-list 1,575 ) (1.26 for Laravel 13 2,157 ).