Hay muchas situaciones en Laravel donde simplemente necesitas un array de IDs de un conjunto de modelos. Nada sofisticado: sin campos extra, sin transformaciones… solo los identificadores.
Suena sencillo, pero una vez que empiezas a trabajar con relaciones de Eloquent, claves primarias no estándar o tablas grandes, la decisión entre pluck() y modelKeys() en realidad importa más de lo que parece.
Me he topado con este mismo problema muchas veces, así que vamos a desglosarlo adecuadamente.
El problema común: obtener un array de IDs en Laravel
Un escenario muy típico se ve así:
- Tienes una relación
hasMany - Un modelo ya cargado
- Necesitas los IDs de los modelos relacionados
Por ejemplo, un Role que tiene muchos modelos Permission.
En ese punto, usualmente ya tienes una Colección de Eloquent, no un constructor de consultas (query builder) — y ese detalle es clave.
Trabajando con relaciones de Eloquent (ejemplo hasMany)
$permissionIDs = $role->permissions->pluck('id'); Esto funciona, es legible y la mayoría de los desarrolladores de Laravel lo usan por instinto. Y honestamente, en proyectos reales, esto sigue siendo lo que utilizo la mayor parte del tiempo.
Pero hay un truco
Uso de pluck() para extraer IDs de una Colección
Uso básico de pluck('id')
pluck() extrae un atributo dado de cada modelo en la colección y devuelve una nueva colección que contiene esos valores.
$permissionIDs = $role->permissions->pluck('id'); Luego puedes llamar a ->toArray() si realmente necesitas un array plano.
Cuándo pluck() es la opción más segura
Por experiencia, pluck() es la opción predeterminada más segura cuando:
- Quieres una columna específica
- Es posible que luego cambies el nombre de la clave
- No estás 100% seguro de cómo se construyó la colección
Funciona en:
- Constructores de consultas (Query builders)
- Modelos de Eloquent
- Colecciones de Eloquent
Esa flexibilidad por sí sola hace que sea difícil de superar.
Formateo de valores con cierres (closures) en pluck()
Aquí es donde pluck() realmente brilla, especialmente después de que se introdujera el soporte para cierres.
Por ejemplo:
Product::available()->get() ->pluck(fn ($product) => "{$product->brand} {$product->model}", 'id'); Sin map() extra. Sin mapWithKeys(). Sin transformaciones intermedias.
He usado mucho esto en vistas de Blade para menús desplegables. Mantiene clara la intención y el código encadenable.
Uso de modelKeys(): qué hace realmente
A primera vista, modelKeys() parece un atajo ingenioso:
$permissionIDs = $role->permissions->modelKeys(); Mismo resultado. Misma cantidad de caracteres. Un poco más "cool"
Pero, ¿qué está haciendo realmente?
Cómo funciona modelKeys() internamente
modelKeys() simplemente devuelve:
“El array de claves primarias de los modelos en la colección.”
Eso es todo.
Sin transformaciones. Sin formateo. Sin flexibilidad.
Claves primarias y nombres de clave no estándar
Una ventaja de modelKeys() es que respeta las claves primarias personalizadas.
Si tu modelo usa algo distinto a id, modelKeys() seguirá funcionando correctamente — mientras que pluck('id') obviamente fallaría a menos que cambies el nombre de la columna.
Esa suele ser la primera razón por la que los desarrolladores notan este método.
Por qué modelKeys() solo funciona en Colecciones
Esta parte confunde a la gente todo el tiempo.
❌ Esto fallará:
Permission::modelKeys(); Porque modelKeys() no existe en el modelo ni en el constructor de consultas.
✅ Esto funciona:
Permission::all()->modelKeys(); Pero aquí está la trampa — y esto es importante en proyectos reales.
Cargar todos los registros en memoria solo para extraer los IDs puede ser un problema de rendimiento serio en tablas grandes. He visto esto hecho accidentalmente más de una vez.
pluck() vs modelKeys(): diferencias clave
Flexibilidad vs simplicidad
pluck()→ flexible, expresivo, funciona en todas partesmodelKeys()→ simple, estricto, solo para colecciones
Si necesitas cualquier cosa más allá de “simplemente dame las claves primarias”, pluck() gana de inmediato.
Consideraciones de rendimiento
En la práctica:
pluck('id')puede ejecutarse a nivel de consulta (base de datos)modelKeys()requiere una colección ya cargada
Eso por sí solo convierte a pluck() en la mejor opción cuando el rendimiento importa.
Errores comunes y conceptos erróneos
Un malentendido común es pensar que modelKeys() es de alguna manera “más eficiente” porque suena a un nivel más bajo.
No lo es.
Si ya tienes la colección cargada, claro — está bien.
Si no la tienes, forzar un all() completo solo para llamar a modelKeys() suele ser una mala idea.
Errores comunes al extraer valores de modelos de Eloquent
Por qué only() no funciona en los atributos del modelo
Esto surge a menudo (y hay un hilo clásico de Laracasts al respecto).
only() funciona sobre las claves de la colección, no sobre los atributos del modelo.
Así que esto devolverá una colección vacía:
$options->only('responses'); Porque responses vive dentro de cada modelo, no al nivel de la colección.
Colección vs Modelo: el modelo mental
Este es el cambio mental clave que resuelve la mayoría de las confusiones:
- Las colecciones contienen modelos
- Los métodos de colección no acceden mágicamente a los atributos del modelo
Una vez que interiorizas eso, pluck() de repente tiene todo el sentido del mundo — y métodos como only() dejan de ser tentadores en los lugares equivocados.
¿Cuál deberías usar en proyectos reales?
Reglas de decisión claras
Usa pluck() cuando:
- No tienes una colección ya cargada
- Necesitas flexibilidad o formateo
- El rendimiento es importante
- Quieres un comportamiento predecible en todas partes
Usa modelKeys() cuando:
- Ya tienes una colección cargada
- Solo te interesan las claves primarias
- El nombre de la clave primaria puede variar
Lo que realmente uso la mayor parte del tiempo
En aplicaciones Laravel del mundo real, sigo usando pluck('id') por defecto.
Es útil conocer modelKeys() — y me alegra que exista — pero es más un método de “interesante de saber” que algo que utilice a diario.
Preguntas frecuentes
¿Es modelKeys() más rápido que pluck()?
No. En todo caso, pluck() suele ser más eficiente porque puede ejecutarse a nivel de consulta.
¿Puede pluck() devolver valores formateados?
Sí. Con cierres (closures), es extremadamente potente y reemplaza muchos casos de uso de map().
¿Funciona modelKeys() en modelos de Eloquent?
No. Solo en colecciones de Eloquent.
¿Puedo obtener IDs sin cargar los modelos completos?
Sí — usa pluck() directamente en la consulta (query).
Conclusión
Tanto pluck() como modelKeys() resuelven el mismo problema a nivel superficial, pero viven en capas diferentes de Eloquent.
Si entiendes cuándo estás tratando con una colección frente a una consulta, la elección correcta se vuelve obvia casi siempre.
Conoce modelKeys().
Usa pluck().