끝없는 마이그레이션 작성 그만하기: Laravel에서 PostgreSQL JSONB 마스터하기
Source: Dev.to

“Settings” 테이블 악몽
모든 SaaS 애플리케이션은 결국 같은 구조적 벽에 부딪힙니다: 동적 데이터. users 테이블이 있는데, 갑자기 제품 매니저가 사용자가 다크 모드 선호도를 저장하도록 하고 싶어합니다. theme 컬럼을 추가하는 마이그레이션을 작성합니다. 다음 주에는 notification_time 선호도를 추가하고 싶어합니다. 또 다른 마이그레이션. 곧 테이블에 대부분 비어 있는 40개의 nullable 컬럼이 생깁니다.
일부 개발자는 이를 해결하기 위해 MongoDB 같은 NoSQL 데이터베이스로 완전히 전환하려고 합니다. 하지만 그러면 관계 무결성, ACID 준수, 외래 키와 같은 강력한 기능을 잃게 됩니다.
궁극적인 해결책은 PostgreSQL 안에 바로 있습니다: JSONB 컬럼.
JSONB의 힘
PostgreSQL은 컬럼에 원시 JSON 데이터를 저장할 수 있게 해줍니다. 하지만 일반 텍스트 필드와 달리 JSONB(JSON Binary) 타입은 실제로 파싱되어 커스텀 바이너리 형식으로 저장됩니다. 이는 PostgreSQL이 이를 인덱싱하고, 쿼리하고, 표준 정수 컬럼만큼 빠르게 필터링할 수 있음을 의미합니다.
Laravel 마이그레이션에서는 매우 간단하게 설정할 수 있습니다:
Schema::table('users', function (Blueprint $table) {
// 모든 것을 지배하는 하나의 컬럼
$table->jsonb('preferences')->default('{}');
});
Eloquent에서의 캐스팅
Laravel의 Eloquent ORM은 JSONB와 작업하는 것을 마법처럼 만들어 줍니다. 모델에 배열 캐스트를 추가하면, Laravel은 데이터베이스 JSON을 읽을 때 자동으로 네이티브 PHP 배열로 변환하고, 저장할 때 다시 JSON으로 변환합니다.
class User extends Model
{
protected $casts = [
'preferences' => 'array',
];
}
이제 또 다른 마이그레이션을 작성하지 않고도 동적 설정을 업데이트할 수 있습니다:
$user = User::find(1);
$user->preferences['theme'] = 'dark';
$user->preferences['marketing_emails'] = false;
$user->save();
JSON 내부 쿼리
JSONB이기 때문에 Laravel의 화살표 구문을 사용해 JSON 페이로드 내부 키에 직접 매우 빠른 쿼리를 작성할 수 있습니다.
// 다크 테마가 활성화된 모든 사용자를 찾기
$darkUsers = User::where('preferences->theme', 'dark')->get();
결론
동적 데이터를 처리하기 위해 NoSQL 데이터베이스가 필요하지 않습니다. PostgreSQL의 엄격한 관계형 파워와 JSONB 컬럼의 유연성, 그리고 Laravel Eloquent 캐스팅을 결합하면, 필요한 곳에서는 견고하고, 다른 모든 곳에서는 무한히 유연한 데이터베이스를 설계할 수 있습니다.