Laravel Eloquent: Como obter apenas algumas colunas de tabelas unidas

102

Eu tenho 2 tabelas unidas no Eloquent: temas e usuários.

modelo de tema:

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

modelo de usuário:

public function themes() {
  return $this->has_many('Theme');
}

Minha chamada de API do Eloquent é a seguinte:

return Response::eloquent(Theme::with('user')->get());

O que retorna todas as colunas do tema (isso é bom) e todas as colunas do usuário (não está bem). Eu preciso apenas da coluna 'nome de usuário' do modelo de usuário, como posso limitar a consulta a isso?

ralu
fonte
Estou trabalhando em uma tarefa semelhante, posso saber se estou usando Responseque tipo de classe preciso importar?
Agnes Palit

Respostas:

103

Altere seu modelo para especificar quais colunas você deseja selecionar:

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

E não se esqueça de incluir a coluna à qual você está ingressando.

user2317976
fonte
6
ótima resposta, também a dica sobre a inclusão da coluna join me economizou muito tempo!
greatwitenorth
E se em alguns lugares eu precisar apenas de id em vez de id e nome de usuário? Ainda tem que selecionar ambos?
Darius.V
Olá, a função de seleção tem a mesma função no construtor de consulta de modelo?
Gokigooooks de
4
Não acho que seja uma boa abordagem. Será uma espécie de codificação dos nomes das colunas. Todos os lugares retornarão apenas essas colunas. Em alguma outra API, posso precisar de mais algumas colunas, então isso não funcionará aqui. Acho que usar QueryBuilder é a opção aqui.
Aman Sura
2
Esta é uma abordagem dramática, pois ocorrerá toda vez que você fizer a chamada no futuro. Eu acredito que a resposta de Sajjad Ashraf é aquela em que a maioria das pessoas vai se interessar.
MMMTroy
37

Para Laravel> = 5,2

Use o método -> pluck ()

$roles = DB::table('roles')->pluck('title');

Se você gostaria de recuperar um array contendo os valores de uma única coluna, você pode usar o método de arrancar


Para Laravel <= 5.1

Use o método -> lists ()

$roles = DB::table('roles')->lists('title');

Este método retornará uma matriz de títulos de função. Você também pode especificar uma coluna de chave personalizada para a matriz retornada:

Javi Stolz
fonte
2
Esta não é realmente uma resposta à pergunta (que era especificamente sobre junções / relacionamentos).
ou
30

Você pode fornecer uma matriz de campos no parâmetro get como:

return Response::eloquent(Theme::with('user')->get(array('user.username'));

ATUALIZAÇÃO (para Laravel 5.2) A partir da documentação , você pode fazer o seguinte:

$response = DB::table('themes')
    ->select('themes.*', 'users.username')
    ->join('users', 'users.id', '=', 'themes.user_id')
    ->get();
Melvin
fonte
2
Tentei fazer isso e mostra um erro SQLSTATE[42S22]: Column not founde seu SQL não inclui a tabela no with. O sql que aparece no erro é "SELECT fk_table.column1 FROM main_table".
Michel Ayres
1
É "users.username" (não "user.username"). O código na resposta funcionará se você tiver os nomes das tabelas e colunas correspondentes ao seu banco de dados real. Essa é a desvantagem dessa solução, ela está construindo uma consulta SQL em vez de usar o Eloquent, então os nomes devem corresponder às tabelas e colunas reais do banco de dados.
ou
22

Eu sei, você pede Eloquent, mas você pode fazer isso com o Fluent Query Builder

$data = DB::table('themes')
    ->join('users', 'users.id', '=', 'themes.user_id')
    ->get(array('themes.*', 'users.username'));
Aykut
fonte
16

É assim que eu faço

$posts = Post::with(['category' => function($query){
        $query->select('id', 'name');
      }])->get();

A primeira resposta do usuário 2317976 não funcionou para mim, estou usando o laravel 5.1

Sajjad Ashraf
fonte
2
Resposta atualizada = útil!
thesunneversets de
Obrigado. Isso funciona bem para mim. Devo adicionar a chave estrangeira na instrução select como você fez com 'id', caso contrário, ele retorna nulo.
Iman Sedighi
No entanto, isso ainda recupera um campo "pivô" para cada resultado, contendo ambos os ids (post_id e category_id) certo? Como posso me livrar disso?
mayid,
1
@mayid, você pode tentar adicionar pivot$ array oculto de Post Modelprotected $hidden = ['pivot']
Sajjad Ashraf
Esta é a melhor solução (supondo que você esteja usando uma versão bastante moderna do Laravel)
ou
11

Outra opção é fazer uso da $hiddenpropriedade no modelo para ocultar as colunas que você não deseja exibir. Você pode definir essa propriedade em tempo real ou definir padrões em seu modelo.

public static $hidden = array('password');

Agora, a senha do usuário será ocultada quando você retornar a resposta JSON.

Você também pode configurá-lo em tempo real de maneira semelhante.

User::$hidden = array('password');
Jason Lewis
fonte
2
no Laravel 4.2 estou obtendo 'Não é possível acessar a propriedade protegida User :: $ hidden' quando tento configurar isso dinamicamente.
mtmacdonald
1
não deveria ser static.
StackOverflowed em
@StackOverflowed, suponho que você não percebeu a idade desta pergunta / resposta e que ela se relacionava com o Laravel 3.
Jason Lewis
10

Usando com paginação

$data = DB::table('themes')
->join('users', 'users.id', '=', 'themes.user_id')
->select('themes.*', 'users.username')
->paginate(6);
Nufayl
fonte
6

user2317976 introduziu uma ótima maneira estática de selecionar colunas de tabelas relacionadas.

Aqui está um truque dinâmico que descobri para que você possa obter o que quiser ao usar o modelo:

return Response::eloquent(Theme::with(array('user' => function ($q) {
    $q->addSelect(array('id','username'))
}))->get();

Acabei de descobrir que esse truque também funciona bem com load (). Isso é muito conveniente.

$queriedTheme->load(array('user'=>function($q){$q->addSelect(..)});

Certifique-se de incluir também a chave da tabela de destino, caso contrário, ela não será capaz de encontrá-la.

KinoP
fonte
6

Deste jeito:

Post::with(array('user'=>function($query){
    $query->select('id','username');
}))->get();
Especificações
fonte
Sempre explique sua resposta.
Rohit Gupta
Tive um problema parecido, essa é a maneira mais inteligente até agora! Esta resposta é subestimada!
eldblz
Esta é a mesma resposta que já foi enviada anteriormente por Sajjad Ashraf.
ou
5

Eu sei que essa é uma pergunta antiga, mas se você estiver construindo uma API, como o autor da pergunta faz, use transformadores de saída para executar essas tarefas.

Transofrmer é uma camada entre o resultado real da consulta ao banco de dados e um controlador. Ele permite controlar e modificar facilmente o que será enviado a um usuário ou consumidor de API.

Eu recomendo Fractal como uma base sólida de sua camada de transformação de saída. Você pode ler a documentação aqui .

Armen Markossyan
fonte
4

No Laravel 5.5, a maneira mais limpa de fazer isso é:

Theme::with('user:userid,name,address')->get()

Você adiciona dois pontos e os campos que deseja selecionar separados por uma vírgula e sem espaço entre eles.

JoeGalind
fonte
Você sabe como podemos buscar colunas específicas da tabela relacionada ao usar a paginação.
Daniyal Nasir
2

Usando o modelo:

Model::where('column','value')->get(['column1','column2','column3',...]);

Usando o Query Builder:

DB::table('table_name')->where('column','value')->get(['column1','column2','column3',...]);
srmilon
fonte
0

Se bem entendi isso, o que é retornado está bom, exceto que você deseja ver apenas uma coluna. Nesse caso, o seguinte deve ser muito mais simples:

return Response::eloquent(Theme::with('user')->get(['username']));
Kornel
fonte