Obtenga columnas específicas utilizando la función "Con ()" en Laravel Eloquent

197

Tengo dos mesas Usery Post. Uno Userpuede tener muchos postsy uno postpertenece a uno solo user.

En mi Usermodelo tengo una hasManyrelación ...

public function post(){
    return $this->hasmany('post');
}

Y en mi postmodelo tengo una belongsTorelación ...

public function user(){
    return $this->belongsTo('user');
}

Ahora quiero unir estas dos tablas usando Eloquent with()pero quiero columnas específicas de la segunda tabla. Sé que puedo usar el generador de consultas, pero no quiero hacerlo.

Cuando en el Postmodelo escribo ...

public function getAllPosts() {
    return Post::with('user')->get();
}

Ejecuta las siguientes consultas ...

select * from `posts`
select * from `users` where `users`.`id` in (<1>, <2>)

Pero lo que quiero es ...

select * from `posts`
select id,username from `users` where `users`.`id` in (<1>, <2>)

Cuando uso ...

Post::with('user')->get(array('columns'....));

Solo devuelve la columna de la primera tabla. Quiero columnas específicas usando with()de la segunda tabla. ¿Cómo puedo hacer eso?

Awais Qarni
fuente

Respuestas:

347

Bueno, encontré la solución. Se puede hacer uno pasando una closurefunción with()como segundo índice de matriz como

Post::with(array('user'=>function($query){
    $query->select('id','username');
}))->get();

Solo seleccionará idy usernamede otra tabla. Espero que esto ayude a otros.


Recuerde que la clave primaria (id en este caso) debe ser el primer parámetro en $ query-> select () para recuperar realmente los resultados necesarios. *

Awais Qarni
fuente
1
Eso es extraño, no pude hacer que esto funcione. Tan pronto como agregué $query->select('id','username');, estaba obteniendoTrying to get property of non-object
user1669496 el
55
¡Extraño! Todavía devuelve todos los campos del usuario. @AwaisQarni
justin
2
Gracias por compartir esto. ¿Dónde descubriste esta posibilidad? No encontré esto en los documentos de Laravel.
Symen Timmermans
80
Para aquellos que ven esto, recuerden que la clave primaria ( iden este caso) es necesaria $query->select()para recuperar los resultados necesarios. Omití esto en mi código y no pude entender por qué no encontraría ningún resultado. ¡Tonto de mí! Espero que esto ayude a cualquier otra persona con el mismo problema
Azirius
44
genial, solo necesito agregar una clave foránea, aquí su post_id de lo contrario el resultado estará vacío. Mencionar la clave externa es importante aquí. Gracias :)
Hashaam Ahmed
102

Puedes hacerlo así desde Laravel 5.5:

Post::with('user:id,username')->get();

Cuide el idcampo y foreign keyscomo se indica en los documentos :

Al usar esta función, siempre debe incluir la columna de identificación y las columnas de clave externa relevantes en la lista de columnas que desea recuperar.

Por ejemplo, si el usuario pertenece a un equipo y tiene una team_idcolumna de clave externa, entonces $post->user->teamestá vacía si no especifica team_id

Post::with('user:id,username,team_id')->get();
Adán
fuente
13
No olvide incluir la clave foránea (suponiendo que sea post_id aquí) para resolver la relación, de lo contrario obtendrá resultados vacíos para su relación.
Hashaam Ahmed
2
Esta realmente debería ser la respuesta seleccionada. Funciona como un encanto :)
Graham
@ Adam, esto restringirá las columnas en la tabla secundaria, ¿cómo puedo restringir las columnas de la tabla Tabla principal junto con la tabla secundaria?
Sodio
@GauravGenius todo lo que desea restringir de las pertenencias de los parant en el get()métodoPost::with('user:id,username')->get(['age', 'color']);
Adam
82

En su Postmodelo

public function user()
{
    return $this->belongsTo('User')->select(array('id', 'username'));
}

El crédito original va a Laravel Eager Loading: carga solo columnas específicas

usuario1669496
fuente
14
Pero esta relación lo hará como codificado. En todas las condiciones, siempre me devolverá estos dos campos. Puede suceder que necesite más campos en algunas otras situaciones
Awais Qarni
Luego debe usar el generador de consultas.
user1669496
55
Esta debería ser la respuesta aceptada. Esta es la forma correcta de hacerlo.
BugHunterUK
1
¿Hay alguna manera de hacer esto en la versión Laravel 5.3? Creo que lo cambiaron ... otra vez ... y ahora vuelve nulo cuando intento con este enfoque
Andre F.
Ha pasado un tiempo, pero puedes agregar un $fieldsparámetro.
JordyvD
69

Al ir hacia el otro lado (hasMany):

User::with(array('post'=>function($query){
    $query->select('id','user_id');
}))->get();

No olvide incluir la clave externa (suponiendo que sea user_id en este ejemplo) para resolver la relación, de lo contrario obtendrá cero resultados para su relación.

Thijs
fuente
66
Sí, exactamente, "No te olvides de incluir la clave foránea (suponiendo que sea user_id en este ejemplo)"
aqingsao
debe incluir una columna que defina su relación en los campos seleccionados, en este caso user_id
alimfazeli
Buena captura hermano.
Shahrukh Anwar
asombroso hermano, ese uso de clave externa es realmente importante, por suerte te vi y de lo contrario me habría rascado la cabeza durante horas jajaja. ¡Gracias hombre!
Hashaam Ahmed
34

En Laravel 5.7 puedes llamar a un campo específico como este

$users = App\Book::with('author:id,name')->get();

Es importante agregar un foreign_keycampo en la selección.

hendra1
fuente
11
no se olvide de añadir el extranjero clave de campo
hendra1
2
No olvide notar el comentario de @ hendra1, todos los campos de clave externa también son necesarios junto con la clave primaria, de lo contrario obtendrá una colección en blanco. Amigo me salvó el tiempo. Gracias
Rajesh Vishnani
14

En su Postmodelo:

public function userWithName()
{
    return $this->belongsTo('User')->select(array('id', 'first_name', 'last_name'));
}

Ahora puedes usar $post->userWithName

Duy Hoang
fuente
2
De Verdad? Para mí esto simplemente no devuelve nada, es decir, ¿lo rompe?
Sjwdavies
12

Si desea obtener columnas específicas usando with()laravel elocuente, puede usar el código que se muestra a continuación, que originalmente fue respondido por @Adam en su respuesta aquí en respuesta a esta misma pregunta:

Post::with('user:id,username')->get();

Así que lo he usado en mi código pero me estaba dando un error 1052: Column 'id' in field list is ambiguous, así que si ustedes también enfrentan el mismo problema

Luego, para resolverlo, debe especificar el nombre de la tabla antes de la columna de identificación en el with()método como se muestra a continuación :

Post::with('user:user.id,username')->get();
Haritsinh Gohil
fuente
¡Esto devuelve nulo para mí pero no sabía que esto era posible antes! Ok, publiqué prematuramente pero encontré un resultado. Para usar este método (se ve mucho más limpio) debe incluir el enlace de la relación, por ejemplo, la columna ID al extraer los datos. Sin este especificador, obtienes un retorno nulo.
Adsy2010
sí @ Adsy2010, para obtener datos de relaciones relacionadas, también debe obtener la columna de identificación o la clave principal o la identificación que sea responsable de esa relación.
Haritsinh Gohil
10

Encontré este problema pero con una segunda capa de objetos relacionados. La respuesta de @Awais Qarni se mantiene con la inclusión de la clave externa apropiada en la instrucción de selección anidada. Así como se requiere una identificación en la primera instrucción select anidada para hacer referencia al modelo relacionado, la clave externa se requiere para hacer referencia al segundo grado de modelos relacionados; en este ejemplo el modelo de empresa.

Post::with(['user' => function ($query) {
        $query->select('id','company_id', 'username');
    }, 'user.company' => function ($query) {
        $query->select('id', 'name');
    }])->get();

Además, si desea seleccionar columnas específicas del modelo de publicación, deberá incluir la columna user_id en la instrucción select para hacer referencia a ella.

Post::with(['user' => function ($query) {
        $query->select('id', 'username');
    }])
    ->select('title', 'content', 'user_id')
    ->get();
jwarshaw
fuente
4

Tenga en cuenta que si solo necesita una columna de la tabla, entonces usar 'listas' es bastante bueno. En mi caso, estoy recuperando los artículos favoritos de un usuario, pero solo quiero la identificación del artículo:

$favourites = $user->favourites->lists('id');

Devuelve una matriz de identificadores, por ejemplo:

Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)
omar j
fuente
¡devuelve una colección!
Giovanni Far
si quieres una matriz entonces llama toArray()!!! $user->favourites->lists('id')->toArray();
Giovanni Far
La consulta aún obtendrá las otras columnas porque el método list () solo cambia la matriz de resultados, por lo que si solo necesita el 'id' de esa tabla, es posible que desee especificarlo en la consulta. Siempre es un buen hábito tener en cuenta el rendimiento al hacer consultas. ¡Disfruta codificando!
Ervin Llojku
-1 $user->favouritesserá devuelto Collectioncon todos los campos seleccionados. El uso correcto es: $user->favourites()->lists('id').
Wallace Maxters
Seleccionar todo para usar luego el filtrado de PHP es una mala idea. Es mejor usar solo los campos necesarios en la consulta. Es importante saber la diferencia entre Query\Builder::listsmétodo y Collection::listsmétodo.
Wallace Maxters
1

También puede especificar columnas en el modelo relacionado al momento de acceder a él.

Post::first()->user()->get(['columns....']);

Shreyansh Panchal
fuente
0

Ahora puede usar el pluckmétodo en una Collectioninstancia:

Esto devolverá solo el uuidatributo dePost model

App\Models\User::find(2)->posts->pluck('uuid')
=> Illuminate\Support\Collection {#983
     all: [
       "1",
       "2",
       "3",
     ],
   }
Giovanni Far
fuente
0

Probar con condiciones.

$id = 1;
Post::with(array('user'=>function($query) use ($id){
    $query->where('id','=',$id);
    $query->select('id','username');
}))->get();
Shirjeel Ahmed Khan
fuente
-3
EmployeeGatePassStatus::with('user:id,name')->get();
kush
fuente
1
Esta es la misma sintaxis que en esta respuesta (solo nombres diferentes para modelo y columna)
barbsan