php - order groupBy method by total and get also all rows in laravel

I want to order my products like this, get all products, group them by color, and get first three color with most item.

$products = Products::select('color', DB::raw('count(*) as total'))
    ->groupBy('color')
    ->orderBy('total', 'desc')
    ->limit(3)
    ->get();

but it only gives me something like this:

[
    {
        "color": "red",
        "total": 3
    },
    {
        "color": "blue",
        "total": 2
    },
    {
        "color": "yellow",
        "total": 1
    }
]

with no total, It gives me all rows grouped by color, but I want to get all rows grouped by color and order them with total.

something like this order by each total: (red color comes, then blue and yellow)

{
    "red": [
        {
            "id": 1,
            "title": "first red product",
            "color": "red",
            "created_at": "2022-09-03T23:44:59.000000Z",
            "updated_at": "2022-09-03T23:44:59.000000Z"
        },
        {
            "id": 3,
            "title": "second red product",
            "color": "red",
            "created_at": "2022-09-03T23:45:40.000000Z",
            "updated_at": "2022-09-03T23:45:40.000000Z"
        },
        {
            "id": 6,
            "title": "some red product",
            "color": "red",
            "created_at": "2022-09-03T23:44:59.000000Z",
            "updated_at": "2022-09-03T23:44:59.000000Z"
        }
    ],
    "blue": [
        {
            "id": 2,
            "title": "some blue product",
            "color": "blue",
            "created_at": "2022-09-03T23:45:40.000000Z",
            "updated_at": "2022-09-03T23:45:40.000000Z"
        },
        {
            "id": 4,
            "title": "another blue product",
            "color": "blue",
             "created_at": "2022-09-03T23:45:40.000000Z",
            "updated_at": "2022-09-03T23:45:40.000000Z"
        }
    ],
    "yellow": [
        {
            "id": 5,
            "title": "some yellow product",
            "color": "yellow",
            "created_at": "2022-09-03T23:45:40.000000Z",
            "updated_at": "2022-09-03T23:45:40.000000Z"
        }
    ]
}

Answer

Solution:

You can use collection method: groupBy sortBy count map take all

$products = Products::all()
        ->groupBy('color')
        ->sortBy(fn ($groupValue, $groupKey) => count($groupValue), SORT_REGULAR, true)
        ->map(fn($groupValue, $groupKey) => $groupValue->take(3))
        ->all();

Source