Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Charrua's avatar

Nested grouping 5 levels 🤯

Well, I have some martial arts members from a school, and need to send a belt order to the belt provider.

The issue is, each belt has different details, Belt Type, Belt Size, Belt Color, Special stripe

The idea is to generate this output

Belt type: Classic
Size => 5   Color => Blue   Special stripe => Gold      Quantity => 5
Size => 3   Color => Red    Special stripe => Black     Quantity => 2

Belt type: Black Belt
Size => 5   Color => Black  Special stripe => Gold      Quantity => 5
Size => 3   Color => Black  Special stripe => Gold      Quantity => 2

Belt type: Tiger
Size => 2   Color => Blue   Special stripe => No        Quantity => 5
Size => 1   Color => Green  Special stripe => No        Quantity => 2

If I query members, I can have information for belt type, size, color and stripe. But to generate the output, the way I'm doing it now is grouping the collection by multiple levels. This adds some difficulty because it creates a nested collection with 5 levels and is difficult for me to handle so many levels.

The actual query I'm using for grouping those members

$grouped = $members->groupBy(['belt.type', 'belt.size', '.belt.color', 'belt.stripe']);

The output I get

Collection {#864 â–¼
  #items: array:2 [â–¼
    "Classic" => Collection {#870 â–¼
      #items: array:2 [â–¼
        5 => Collection {#992 â–¼
          #items: array:1 [â–¼
            "Orange" => Collection {#991 â–¼
              #items: array:2 [â–¼
                "Black stripe" => Collection {#958 â–¼
                  #items: array:1 [â–¼
                    0 => TestingCandidate {#953 â–¶}
                  ]
                }
                "Plain" => Collection {#990 â–¼
                  #items: array:1 [â–¼
                    0 => TestingCandidate {#956 â–¶}
                  ]
                }
              ]
            }
          ]
        }
        3 => Collection {#960 â–¼
          #items: array:1 [â–¼
            "Orange" => Collection {#963 â–¼
              #items: array:1 [â–¼
                "Plain" => Collection {#993 â–¼
                  #items: array:1 [â–¼
                    0 => TestingCandidate {#955 â–¶}
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
    "Black Belt" => Collection {#866 â–¼
      #items: array:1 [â–¼
        3 => Collection {#994 â–¼
          #items: array:1 [â–¼
            "Black" => Collection {#1001 â–¼
              #items: array:1 [â–¼
                "Black stripe" => Collection {#951 â–¼
                  #items: array:1 [â–¼
                    0 => TestingCandidate {#954 â–¶}
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

On the frontend I use something like

@foreach ()
    @foreach()
        @foreach()
            @foreach()
            ...
            @endforeach
        @endforeach
    @endforeach
@endforeach

This makes any sense to you? What do you think?

0 likes
2 replies
skauk's avatar
skauk
Best Answer
Level 8

@charrua It looks like you'd be better off with a custom SQL query in this case. Try grouping your belts there and add a raw column with COUNT(). Then you could iterate through the result with a single loop. I can't provide you with a concrete code example but it looks like you'll need to join TestingCandidate table to select the belts you want.

$belts = Belts::query()
    ->join(
        ($testing_candidate = TestingCandidate::getModel())->getTable(), 
        $testing_candidate->getQualifiedKeyName(), '=', 
        $testing_candidate->belts()->->getQualifiedForeignKeyName())
    ->groupBy(['type', 'size', 'color'])
    ->selectRaw('COUNT(*)') 
    ->get(); 
Charrua's avatar

Great idea, I was able to create a custom SQL query with the results I wanted. The main issue about this path at the beginning was that I have many relations on the testing_candidate but I figured it!

Thank you for your help!

Please or to participate in this conversation.