Laravel Eloquent: Storing arrays and nested arrays in database

Updated: January 17, 2024 By: Guest Contributor Post a comment

Introduction

Laravel Eloquent is an ORM (Object-Relational Mapping) that makes it incredibly easy to interact with a database. When working with Eloquent, developers are primarily dealing with model instances which correspond to rows in the database. However, sometimes you may have data in the form of arrays or nested arrays that you’d like to store in a relational database using Eloquent. In this tutorial, we’ll cover how to accomplish this task efficiently.

Understanding JSON Column Type

One of the most straightforward ways to store arrays and nested arrays in a database is by using the JSON column type supported by modern database systems like MySQL and PostgreSQL. Laravel Eloquent ORM can automatically cast the attributes of a model to json, thanks to its $casts property. Let’s see a basic example of how you can create and utilize a JSON column.

use Illuminate\\Database\\Migrations\\Migration;
use Illuminate\\Database\\Schema\\Blueprint;
use Illuminate\\Support\\Facades\\Schema;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            // Defining a JSON column for storing arbitrary data
            $table->json('preferences')->nullable();
            $table->timestamps();
        });
    }
}

In your Eloquent model, you would then use the $casts property to handle the transformation to and from the JSON format automatically:

use Illuminate\\Database\\Eloquent\\Model;

class User extends Model
{
    protected $casts = [
        'preferences' => 'array',
    ];
}

With the above setup, you can now store an array or nested array in the ‘preferences’ attribute, and Eloquent will handle the serialization for you.

Working with Array and Nested Array

With the JSON data type and Eloquent’s casting feature, you can easily store and retrieve arrays and nested arrays from the database. Here’s an example of how to store an array and a nested array:

$user = new User();
$user->name = 'John Doe';
$user->preferences = [
    'language' => 'English',
    'notifications' => [
        'email' => true,
        'sms' => false,
    ],
];
$user->save();

You can also update your nested arrays and work with arrays as if they were regular PHP arrays:

$user = User::find(1);
$user->preferences['notifications']['sms'] = true;
$user->save();

When you retrieve the user from the database, the ‘preferences’ array is returned as a PHP array, allowing you to interact with it easily.

$user = User::find(1);
$smsPreference = $user->preferences['notifications']['sms'];

Advanced Scenarios: Mutators and Accessors

In more complex scenarios, you might want to perform operations on these arrays before saving them or after fetching them from the database. Laravel’s accessors and mutators can come in handy for such cases. Below is an example of a mutator that runs before storing the data in the database and an accessor that manipulates the data when it is accessed on the model.

use Illuminate\\Database\\Eloquent\\Model;

// User Model
public function setPreferencesAttribute($value)
{
    $this->attributes['preferences'] = json_encode($value);
}

public function getPreferencesAttribute($value)
{
    return array_merge(json_decode($value, true), [
        'default' => 'values',
    ]);
}

Handling Complex Queries on JSON Columns

Laravel also provides robust support for querying JSON columns. However, queries against JSON columns can sometimes be complex and are subject to the specific capabilities of the database system you’re using. Ensure that your database supports JSON queries and indexing to get the highest performance.

// Query users with English language preference
$users = User::whereJsonContains('preferences->language', 'English')->get();

// Query users who opt-in for email notifications
$users = User::whereJsonContains('preferences->notifications->email', true)->get();

It is also possible to update JSON values directly:

// Increase points within a nested array without retrieving the user
User::where('id', 1)
    ->update(['preferences->points' => \\DB::raw('preferences->"$[*].points" + 50')]);

Remember to test these types of queries and optimize them for your specific use case to prevent performance issues.

Conclusion

By using Laravel’s Eloquent ORM to handle arrays and nested arrays in your database, you can store and manipulate structured data with ease. The use of JSON columns, combined with Eloquent’s casting capabilities, allows for seamless interaction with complex data structures. Just bear in mind that optimizing and querying JSON data can present its own set of challenges that will depend on your particular database engine capabilities.