Obter colunas específicas usando a função “With ()” no Laravel Eloquent

196

Eu tenho duas mesas Usere Post. Um Userpode ter muitosposts e um postpertence a apenas um user.

No meu Usermodelo eu tenho uma hasManyrelação ...

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

E no meu postmodelo eu tenho uma belongsTorelação ...

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

Agora eu quero juntar essas duas tabelas usando Eloquent with() mas quero colunas específicas da segunda tabela. Sei que posso usar o Query Builder, mas não quero.

Quando no Postmodelo eu escrevo ...

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

Ele executa as seguintes consultas ...

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

Mas o que eu quero é ...

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

Quando eu uso ...

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

Ele retorna apenas a coluna da primeira tabela. Quero colunas específicas usando a with()partir da segunda tabela. Como eu posso fazer isso?

Awais Qarni
fonte

Respostas:

346

Bem, eu encontrei a solução. Isso pode ser feito passando uma closurefunção with()como segundo índice da matriz, como

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

Ele selecionará apenas ide usernamede outra tabela. Espero que isso ajude os outros.


Lembre-se de que a chave primária (neste caso, id) precisa ser o primeiro parâmetro em $ query-> select () para recuperar os resultados necessários. *

Awais Qarni
fonte
1
Estranho, eu não consegui fazer isso funcionar. Assim que eu adicionei $query->select('id','username');, eu estava recebendo #Trying to get property of non-object
user1669496 12/12/2013
5
Esquisito! ainda retorna todos os campos do usuário. @AwaisQarni
justin
2
Obrigado por compartilhar isso. Onde você descobriu essa possibilidade? Não encontrei isso nos documentos do Laravel.
Symen Timmermans
80
Para quem vê isso, lembre-se de que a chave primária ( idneste caso) é necessária $query->select()para recuperar os resultados necessários. Omiti isso no meu código e não consegui descobrir por que ele não encontrou nenhum resultado. Parvo eu! Espero que isso ajude alguém com o mesmo problema
Azirius
4
ótimo, só preciso adicionar chave estrangeira, aqui o resultado post_id, caso contrário, ficará vazio. Mencionar chave estrangeira é importante aqui. Obrigado :)
Hashaam Ahmed
102

Você pode fazer isso assim desde o Laravel 5.5:

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

Cuide do idcampo e foreign keysconforme indicado nos documentos :

Ao usar esse recurso, você sempre deve incluir a coluna de identificação e quaisquer colunas relevantes de chave estrangeira na lista de colunas que deseja recuperar.

Por exemplo, se o usuário pertence a uma equipe e tem uma team_idcoluna de chave estrangeira, então$post->user->team vazio se você não especificar team_id

Post::with('user:id,username,team_id')->get();
Adão
fonte
13
Não se esqueça de incluir a chave estrangeira (supondo que seja post_id aqui) para resolver o relacionamento, caso contrário, você obterá resultados vazios para o seu relacionamento.
Hashaam Ahmed 28/11
2
Esta deve realmente ser a resposta selecionada. Funciona como um encanto :)
Graham
@ Adam, isso restringirá as colunas da tabela filho, como posso restringir as colunas da tabela Tabela pai junto com a tabela filho?
Sódio
@GauravGenius tudo o que você quiser restringir a partir belogns Parant no get()métodoPost::with('user:id,username')->get(['age', 'color']);
Adam
82

No seu Postmodelo

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

O crédito original vai para o Laravel Eager Loading - Carrega apenas colunas específicas

user1669496
fonte
14
Mas essa relação tornará exatamente como codificada. Em todas as condições, ele sempre me retornará esses dois campos. Pode acontecer que eu preciso de mais campos em algumas outras situações
Awais Qarni
Então você deve usar o construtor de consultas.
user1669496
5
Essa deve ser a resposta aceita. Esta é a maneira correta de fazer isso.
BugHunterUK
1
Existe uma maneira de fazer isso na versão Laravel 5.3? Eu acho que eles mudaram ... novamente .... e agora ele retorna nulo quando tento com esta abordagem
Andre F.
Já faz um tempo, mas você pode adicionar um $fieldsparâmetro.
21817 JordyvD
69

Ao seguir para o outro lado (hasMany):

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

Não se esqueça de incluir a chave estrangeira (assumindo que seja user_id neste exemplo) para resolver o relacionamento, caso contrário, você obterá zero resultado para o seu relacionamento.

Thijs
fonte
6
Sim, exatamente, "Não se esqueça de incluir a chave estrangeira (assumindo que seja user_id neste exemplo)"
aqingsao 15/06/16
você deve incluir coluna que define o seu relacionamento em alguns campos, neste caso user_id
alimfazeli
Bom irmão pegar.
Shahrukh Anwar 25/09
mano impressionante, que o uso de chave estrangeira é realmente importante, sorte eu vi o seu ans caso contrário, eu teria coçado a cabeça por horas lol. Valeu cara!
Hashaam Ahmed 28/11
34

No Laravel 5.7, você pode chamar um campo específico como este

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

É importante adicionar foreign_keycampo na seleção.

hendra1
fonte
11
não esqueça de adicionar o campo de chave estrangeira
hendra1 27/02
2
Não se esqueça de observar o comentário de @ hendra1, todos os campos de chave estrangeira também são necessários junto com a chave primária, caso contrário, você receberá uma coleção em branco. Cara economizou meu tempo. Obrigado
Rajesh Vishnani
14

No seu Postmodelo:

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

Agora você pode usar $post->userWithName

Duy Hoang
fonte
2
Realmente? Para mim, isso não retorna nada, ou seja, quebra?
precisa saber é o seguinte
12

Se você deseja obter colunas específicas usando o with()laravel eloquent, pode usar o código abaixo, que é originalmente respondido por @Adam em sua resposta aqui em resposta a esta mesma pergunta:

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

Então, eu usei no meu código, mas estava me dando erro de 1052: Column 'id' in field list is ambiguous, então se vocês também estão enfrentando o mesmo problema

Para resolvê- lo , você deve especificar o nome da tabela antes da coluna id no with()método como abaixo do código :

Post::with('user:user.id,username')->get();
Haritsinh Gohil
fonte
Isso retorna nulo para mim, mas eu não sabia que isso era possível antes! Ok, então eu postei prematuramente, mas encontrei um resultado. Para usar esse método (parece muito mais limpo), você deve incluir o link de relacionamento, por exemplo, a coluna ID ao extrair os dados. Sem esse especificador, você obtém um retorno nulo.
Adsy2010 16/06
Sim, no Adsy2010, para obter dados de relacionamento relacionados, você também precisa obter a coluna de ID ou a chave primária ou o ID que for responsável por esse relacionamento.
Haritsinh Gohil 17/06
10

Me deparei com esse problema, mas com uma segunda camada de objetos relacionados. A resposta do @Awais Qarni se mantém com a inclusão da chave estrangeira apropriada na instrução de seleção aninhada. Assim como um id é necessário na primeira instrução de seleção aninhada para referenciar o modelo relacionado, a chave estrangeira é necessária para referenciar o segundo grau de modelos relacionados; neste exemplo, o modelo da empresa.

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

Além disso, se você quiser selecionar colunas específicas do modelo Post, precisará incluir a coluna user_id na instrução select para fazer referência a ela.

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

Observe que, se você precisar apenas de uma coluna da tabela, usar 'lists' é muito bom. No meu caso, estou recuperando os artigos favoritos de um usuário, mas quero apenas os IDs do artigo:

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

Retorna uma matriz de IDs, por exemplo:

Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)
omar j
fonte
retorna uma coleção!
Giovanni Far
se você quiser uma matriz, chame toArray()!!! $user->favourites->lists('id')->toArray();
Giovanni Far
A consulta ainda receberá as outras colunas porque o método list () apenas altera a matriz de resultados, portanto, se você precisar apenas do 'id' dessa tabela, poderá especificá-lo na consulta. É sempre um bom hábito manter o desempenho em mente ao fazer consultas. Aproveite a codificação!
Ervin Llojku 11/03/16
-1 $user->favouritesserá retornado Collectioncom todos os campos selecionados. O uso correto é: $user->favourites()->lists('id').
precisa saber é o seguinte
Selecionar tudo para usar posteriormente a filtragem PHP é uma má ideia. É melhor usar apenas os campos necessários na consulta. É importante saber a diferença entre Query\Builder::listsmétodo e Collection::listsmétodo.
precisa saber é o seguinte
1

Você também pode especificar colunas no modelo relacionado no momento de acessá-lo.

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

Shreyansh Panchal
fonte
0

Agora você pode usar o pluckmétodo em umCollection instância:

Isso retornará apenas o uuidatributo doPost model

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

Tente com as condições.

$id = 1;
Post::with(array('user'=>function($query) use ($id){
    $query->where('id','=',$id);
    $query->select('id','username');
}))->get();
Shirjeel Ahmed Khan
fonte
-3
EmployeeGatePassStatus::with('user:id,name')->get();
kush
fonte
1
Esta é a mesma sintaxe como em esta resposta (apenas nomes diferentes para o modelo e coluna)
barbsan