Query JSON columns and array attributes efficiently using whereJsonContains() and whereJsonLength() in Eloquent.
When storing JSON columns in MySQL, PostgreSQL, or SQLite (such as user preferences, tag arrays, or metadata payloads), filtering rows that contain a specific array value is supported natively by Eloquent.
Querying JSON Arrays
use App\Models\User;
// Finds users who have 'admin' in their JSON 'roles' array column
$admins = User::whereJsonContains('roles', 'admin')->get();
Querying Multiple JSON Values
Pass an array to find rows that contain all or any of the specified values:
// User must have both 'editor' AND 'publisher'
$editors = User::whereJsonContains('roles', ['editor', 'publisher'])->get();
// User must have either 'editor' OR 'publisher'
$staff = User::whereJsonContainsKey('roles', 'editor')
->orWhereJsonContains('roles', 'publisher')
->get();
Querying Nested JSON Object Attributes
// Query nested key: { "settings": { "theme": "dark" } }
$darkThemeUsers = User::where('settings->theme', 'dark')->get();
Querying Array Length with whereJsonLength()
// Finds users with 3 or more configured roles
$multiRoleUsers = User::whereJsonLength('roles', '>=', 3)->get();
Summary
- Uses native database JSON functions (
JSON_CONTAINS,jsonb_exists). - Works on both simple JSON arrays and nested object dictionaries.
- Supports length comparisons via
whereJsonLength().
Related Tips
View all tips →Refresh and Pessimistically Lock Models with refreshForUpdate() in Laravel 13.27
Laravel 13.27 adds refreshForUpdate(), reloading an existing model instance in-place with fresh database attributes while acquiring an exclusive FOR UPDATE row lock.
Scope Pivot Table Queries with Closures in wherePivot() in Laravel 13.26
Laravel 13.26 allows wherePivot() and orWherePivot() to accept closures, enabling direct reuse of local scopes defined on custom Pivot models.