> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Introducción a las relaciones de Eloquent

> Aprende a definir con Eloquent las relaciones entre tablas (uno a uno, uno a muchos y muchos a muchos) y a obtener los datos relacionados de forma eficiente.

## Qué es una relación

Las tablas de una base de datos suelen estar relacionadas entre sí. Por ejemplo, un post de un blog puede tener múltiples comentarios, o un pedido está asociado al usuario que lo realizó.

Eloquent facilita la definición y la manipulación de esas relaciones entre tablas. Cada relación se define como un método del modelo Eloquent.

<Info>
  Esta página utiliza modelos concretos como `User`, `Post`, `Comment` y `Tag` a modo de ejemplo.
  Se asume que dichos modelos y sus tablas ya están creados.
</Info>

Las principales relaciones que soporta Eloquent son:

| Relación        | Descripción                                        |
| --------------- | -------------------------------------------------- |
| `hasOne`        | Uno a uno (el padre tiene un único hijo)           |
| `belongsTo`     | Inversa del uno a uno (el hijo pertenece al padre) |
| `hasMany`       | Uno a muchos (el padre tiene varios hijos)         |
| `belongsToMany` | Muchos a muchos (usa una tabla intermedia)         |

```mermaid theme={null}
erDiagram
    users ||--o| profiles : "hasOne / belongsTo (profiles.user_id)"
    posts ||--o{ comments : "hasMany / belongsTo (comments.post_id)"
    posts }o--o{ tags : "belongsToMany (tabla pivote post_tag)"
```

## hasOne (uno a uno)

`hasOne` representa una relación en la que un modelo tiene un único modelo relacionado. Por ejemplo, cuando un `User` tiene un `Profile`.

### Definir la relación

Define el método `profile` en el modelo `User`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;

class User extends Model
{
    public function profile(): HasOne
    {
        return $this->hasOne(Profile::class);
    }
}
```

Eloquent infiere la clave foránea a partir del nombre del modelo padre. En este caso, asume que la tabla `profiles` contiene la columna `user_id`.

### Obtener los datos relacionados

Puedes acceder a la relación como si fuera una propiedad.

```php theme={null}
$user = User::find(1);
$profile = $user->profile;
```

<Tip>
  Al acceder al método de relación como si fuera una propiedad, Eloquent lanza automáticamente la consulta y te devuelve los datos relacionados. A esto se le llama «propiedad dinámica de relación».
</Tip>

## belongsTo (inversa del uno a uno)

`belongsTo` es la relación inversa de `hasOne` y se define en el modelo que posee la clave foránea. Representa que `Profile` pertenece a `User`.

### Definir la relación

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Profile extends Model
{
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}
```

Eloquent usa como clave foránea el nombre del método de relación con el sufijo `_id` (en este caso, `user_id`).

### Obtener los datos relacionados

```php theme={null}
$profile = Profile::find(1);
$user = $profile->user;

echo $user->name;
```

## hasMany (uno a muchos)

`hasMany` es la relación más habitual: un modelo padre tiene varios modelos hijos. Por ejemplo, un `Post` tiene varios `Comment`.

### Definir la relación

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Post extends Model
{
    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }
}
```

Eloquent asume que la tabla `comments` contiene la columna `post_id`.

### Obtener los datos relacionados

Una relación `hasMany` devuelve una colección.

```php theme={null}
$post = Post::find(1);

foreach ($post->comments as $comment) {
    echo $comment->body;
}
```

También puedes añadir condiciones a la consulta.

```php theme={null}
$recentComments = Post::find(1)
    ->comments()
    ->latest()
    ->take(5)
    ->get();
```

### Relación inversa (belongsTo)

Para acceder al post desde un comentario, define `belongsTo` en el modelo `Comment`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Comment extends Model
{
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}
```

```php theme={null}
$comment = Comment::find(1);
echo $comment->post->title;
```

## belongsToMany (muchos a muchos)

Usa una relación muchos a muchos cuando ambos modelos pueden estar asociados a múltiples registros del otro lado. Por ejemplo, un `Post` tiene varios `Tag` y cada `Tag` pertenece a varios `Post`.

### Estructura de tablas

Muchos a muchos requiere una tabla intermedia. Para `Post` y `Tag` se prepara la tabla pivote `post_tag`.

```text theme={null}
posts
    id - integer
    title - string

tags
    id - integer
    name - string

post_tag
    post_id - integer
    tag_id - integer
```

<Info>
  Eloquent infiere el nombre de la tabla pivote uniendo alfabéticamente los nombres de los dos modelos relacionados (`post` + `tag` → `post_tag`).
</Info>

### Definir la relación

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Post extends Model
{
    public function tags(): BelongsToMany
    {
        return $this->belongsToMany(Tag::class);
    }
}
```

Si defines lo mismo en el modelo `Tag`, puedes acceder a los datos en sentido inverso.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Tag extends Model
{
    public function posts(): BelongsToMany
    {
        return $this->belongsToMany(Post::class);
    }
}
```

### Obtener los datos relacionados

```php theme={null}
$post = Post::find(1);

foreach ($post->tags as $tag) {
    echo $tag->name;
}
```

### Añadir y eliminar relaciones

`attach` añade un registro a la tabla pivote y `detach` lo elimina.

```php theme={null}
$post = Post::find(1);

// Añadir etiqueta
$post->tags()->attach($tagId);

// Eliminar etiqueta
$post->tags()->detach($tagId);

// Reemplazar todas las relaciones actuales
$post->tags()->sync([$tagId1, $tagId2]);
```

<Tip>
  Con `sync` se eliminan automáticamente los registros de la tabla pivote que no estén en el array, dejando únicamente los IDs indicados como relaciones vigentes.
</Tip>

## Eager loading

### Qué es el problema N+1

Al acceder a una relación como propiedad, Eloquent lanza una consulta cada vez. A esto se le llama «lazy loading» (carga perezosa). Si accedes a una relación dentro de un bucle, se produce el problema N+1.

```php theme={null}
// 1 consulta para obtener todos los posts
$posts = Post::all();

foreach ($posts as $post) {
    // Por cada post se ejecuta una consulta para obtener el usuario (N veces)
    echo $post->user->name;
}
```

Con 100 posts se generarían 101 consultas en total, con el consiguiente impacto en el rendimiento.

### Eager loading con `with()`

Con el método `with()` puedes obtener los datos relacionados de una sola vez, reduciendo el total a solo 2 consultas.

```php theme={null}
// Los posts y sus usuarios en 2 consultas
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // Ya no se lanzan consultas adicionales
    echo $post->user->name;
}
```

Solo se ejecutan estas 2 sentencias SQL:

```sql theme={null}
select * from posts

select * from users where id in (1, 2, 3, ...)
```

### Cargar varias relaciones a la vez

Puedes indicar varias relaciones mediante un array.

```php theme={null}
$posts = Post::with(['user', 'comments', 'tags'])->get();
```

### Eager loading anidado

También puedes cargar relaciones anidadas con notación de punto.

```php theme={null}
// Cargamos los comentarios del post y el usuario de cada comentario
$posts = Post::with('comments.user')->get();
```

<Warning>
  El eager loading es fundamental para evitar el problema N+1. Adopta el hábito de usar `with()` siempre que accedas a relaciones dentro de un bucle.
</Warning>

## Próximos pasos

<Card title="Introducción a Eloquent" icon="database" href="/es/eloquent">
  Repasa las operaciones CRUD básicas de Eloquent.
</Card>


## Related topics

- [API resources de Eloquent](/es/eloquent-resources.md)
- [Introducción a Eloquent](/es/eloquent.md)
- [MongoDB](/es/mongodb.md)
- [Serialización en Eloquent](/es/eloquent-serialization.md)
- [Factorías de Eloquent](/es/eloquent-factories.md)
