staudenmeir/eloquent-json-relations
Adds JSON foreign key support to Laravel Eloquent relationships (belongsTo, hasMany, morph*, through). Also enables many-to-many and has-many-through relations using JSON arrays (IDs or objects) across MySQL, Postgres, SQLite, SQL Server.
Start by installing the package via Composer:
composer require staudenmeir/eloquent-json-relations
Next, add the HasJsonRelations trait to your Eloquent models that need JSON-based relationships. For example, if your Post model stores an array of tag IDs in a json_tags column (e.g., ["tag1", "tag2"]), define a hasMany relationship using the jsonHasMany() method:
use Staudenmeir\EloquentJsonRelations\HasJsonRelations;
class Post extends Model
{
use HasJsonRelations;
public function tags()
{
return $this->jsonHasMany(Tag::class, 'json_tags');
}
}
Your first concrete use case? Fetching a post with its related tags via eager loading:
$post = Post::with('tags')->find($id);
The package handles the JSON extraction, query rewriting, and eager loading behind the scenes—all without touching raw SQL or joins.
jsonHasMany() and jsonBelongsTo() when the foreign key is stored in a JSON array or object path (e.g., meta.author_id for a single scalar or authors.* for arrays).pivot_data->roles) instead of a traditional pivot table row per pair, define jsonBelongsToMany().jsonWhere() or use JSON path syntax like 'pivot_data->>roles[0]' for deeply nested conditions.with(), load(), has(), whereHas(), etc., out of the box.-> (MySQL/Postgres), ->> (Postgres text extraction), and other syntax differences automatically.💡 Tip: Prefer defining paths as clean dot-separated strings ('author.id') where possible—the package normalizes them to DB-specific JSON operators (e.g., JSON_EXTRACT(column, '$.author.id') under the hood).
NULL, empty string, or non-JSON text). Always validate or constrain column values (e.g., JSON_VALID(column) constraints in MySQL).jsonb_path_ops) where query performance matters.jsonBelongsTo(), the package assumes one matching related model. If your JSON array contains duplicates or multiple candidates, use jsonHasMany() + first() or add uniqueness logic at the DB level.protected $casts = ['json_col' => 'array']) on the JSON column used in relationships—this can interfere with the package’s internal query manipulation. Use accessors instead if needed.JsonBelongsToRelationship to add custom path handling (e.g., support for @> operators in Postgres) without modifying core logic.🔧 Debug tip: Enable Laravel’s query log (DB::enableQueryLog()) to see how your JSON relationships are translated into raw SQL—this reveals subtle differences per DB platform.
How can I help you explore Laravel packages today?