73호. 상대 날짜로 그룹핑 하기 free

2019-10-16

라라케스트에서 프로필 > My Feed > Newest Episode 를 보면 다음과 같이 This Week, Last Week, Older와 같이 상대적인 날짜로 묶어서 보여주고 있습니다.



데이터베이스에서 데이터를 가져와 그룹핑 할 때는 크게 두 가지 방법이 있습니다. 하나는 처음부터 SQL로 그룹핑해서 가져오는 것이고, 다른 하나는 데이터를 조회한 후 PHP에서 그룹핑하는 것입니다.


두 방법 모두 장단이 있으니 상황에 맞게 사용하시면 좋을 것 같습니다. SQL로 그룹핑 하는 것은 다소 복잡하긴 해도 다들 경험이 있으실 거라 생각해요. 제프리 웨이가 라라벨 Explained 6번째 에피소드인 Explain How to Group Records By Relative Dates에서 두 번째 방법을 이용해서 상대적인 날짜로 그룹핑하는 팁을 소개했는데, 알아두면 요긴할 것 같아 소개합니다.


쿼리빌더에 groupBy()가 있는 것은 다들 아실텐데요, 컬렉션에도 같은 이름의 매서드가 존재합니다. 쿼리빌더의 groupBy()가 SQL문을 만들어준다면, 컬렉션의 groupBy()는 실제로 그룹을 만듭니다. 아래는 매뉴얼에서 가져온 코드입니다.


$collection = collect([
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
['account_id' => 'account-x11', 'product' => 'Desk'],
]);

$grouped = $collection->groupBy('account_id');

$grouped->toArray();

/*
[
'account-x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'account-x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/

그룹을 지을 키를 문자열로 전달하는 대신 콜백을 전달할 수도 있습니다. 콜백은 해당 아이템이 속할 그룹의 키를 반환해야 합니다.


$grouped = $collection->groupBy(function ($item, $key) {
return substr($item['account_id'], -3);
});

$grouped->toArray();

/*
[
'x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/

상대적인 날짜로 그룹핑을 하는데 바로 이 콜백을 전달하는 기능을 사용합니다.


Route::get('/', function(){
return Video::latest()->get()->groupBy(function($video) {
if($video->created_at->isToday()) {
return 'today';
}

if($video->created_at->isCurrentWeek()) {
return 'this week';
}

if($video->created_at->isLastWeek()) {
return 'last week';
}

return 'older'
})
})

아이템의 생성일이 오늘이면 'today' 그룹에, 이번주면 'this week' 그룹에, 지난 주면 'last week' 그룹에, 그 외에는 'older' 그룹에 넣습니다. isToday(), isCurrentWeek(), isLastWeek()은 모두 Carbon의 매서드입니다. Carbon은 이외에도 많은 비교 매서드를 제공합니다. 가능한 기능 목록은 CarbonComparison 항목을 참고하세요.


마치며


물론, SQL로도 상대적인 날짜로 그룹핑하는게 가능하고 오히려 더 편하게 느끼시는 분들도 계실 수 있습니다. 하지만 저는 저걸 SQL로 짤 생각을 하니 벌써부터 두통이 오는 것 같네요. 컬렉션의 groupBy(), 왠지 앞으로 자주 쓰게 될 것 같네요. :)


1일 1식 라라벨 73호


2019년 10월 16일


이현석

메쉬 코리아 개발자. 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 2020년에 출간될 Laravel Up & Running 2nd Edition을 번역하고 있습니다.