Laravel Eloquent: Comment obtenir uniquement certaines colonnes de tables jointes

102

J'ai 2 tables jointes dans Eloquent, à savoir les thèmes et les utilisateurs.

modèle de thème:

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

modèle d'utilisateur:

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

Mon appel API Eloquent ressemble à ceci:

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

Ce qui renvoie toutes les colonnes du thème (c'est bien) et toutes les colonnes de l'utilisateur (pas bien). Je n'ai besoin que de la colonne «nom d'utilisateur» du modèle utilisateur, comment puis-je limiter la requête à cela?

ralu
la source
Je travaille sur une tâche similaire, puis-je savoir si j'utilise le Responsetype de classe que je dois importer?
Agnes Palit le

Réponses:

103

Modifiez votre modèle pour spécifier les colonnes que vous souhaitez sélectionner:

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

Et n'oubliez pas d'inclure la colonne sur laquelle vous vous joignez.

utilisateur2317976
la source
6
excellente réponse, aussi le conseil sur l'inclusion de la colonne de jointure m'a fait gagner beaucoup de temps!
greatwitenorth
Et si à certains endroits je n'ai besoin que d'un identifiant au lieu de l'identifiant et du nom d'utilisateur? Vous devez encore sélectionner les deux?
Darius.V
Salut, la fonction de sélection a-t-elle la même fonction dans le générateur de requête de modèle?
Gokigooooks
4
Je ne pense pas que ce soit une bonne approche. Ce sera une sorte de codage en dur des noms de colonnes. Tous les emplacements renverront uniquement ces colonnes. Dans une autre API, je peux avoir besoin de quelques colonnes supplémentaires, donc cela ne fonctionnera pas ici. Je pense que l'utilisation de QueryBuilder est l'option ici.
Aman Sura
2
Il s'agit d'une approche dramatique car elle se produira chaque fois que vous passez l'appel. Je crois que la réponse de Sajjad Ashraf est celle qui intéressera le plus les gens.
MMMTroy
37

Pour Laravel> = 5,2

Utilisez la méthode -> pluck ()

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

Si vous souhaitez récupérer un tableau contenant les valeurs d'une seule colonne, vous pouvez utiliser la méthode pluck


Pour Laravel <= 5.1

Utilisez la méthode -> lists ()

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

Cette méthode renverra un tableau de titres de rôle. Vous pouvez également spécifier une colonne de clé personnalisée pour le tableau renvoyé:

Javi Stolz
la source
2
Ce n'est pas vraiment une réponse à la question (qui concernait spécifiquement les jointures / relations).
Orrd
30

Vous pouvez fournir un tableau de champs dans le paramètre get comme ceci:

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

MISE À JOUR (pour Laravel 5.2) À partir de la documentation , vous pouvez faire ceci:

$response = DB::table('themes')
    ->select('themes.*', 'users.username')
    ->join('users', 'users.id', '=', 'themes.user_id')
    ->get();
Melvin
la source
2
J'ai essayé ceci et cela montre une erreur SQLSTATE[42S22]: Column not foundet c'est SQL n'inclut pas la table dans le fichier with. Le sql qui apparaît sur l'erreur est "SELECT fk_table.column1 FROM main_table".
Michel Ayres
1
C'est "users.username" (pas "user.username"). Le code de la réponse fonctionnera si les noms de table et de colonne correspondent à votre base de données réelle. C'est l'inconvénient de cette solution, elle crée une requête SQL plutôt que d'utiliser Eloquent, donc les noms doivent correspondre à vos tables et colonnes de base de données réelles.
Orrd
22

Je sais, vous demandez Eloquent mais vous pouvez le faire avec Fluent Query Builder

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

C'est comme ça que je fais

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

La première réponse de l'utilisateur2317976 n'a pas fonctionné pour moi, j'utilise laravel 5.1

Sajjad Ashraf
la source
2
Réponse à jour = utile!
thesunneversets
Merci. Ça fonctionne bien pour moi. Je dois ajouter la clé étrangère dans l'instruction select comme vous l'avez fait avec 'id' sinon elle retourne null.
Iman Sedighi le
Cependant, cela récupère toujours un champ "pivot" pour chaque résultat, contenant les deux ids (post_id et category_id), n'est-ce pas? Comment puis-je en profiter?
mayid
1
@mayid, vous pouvez essayer d'ajouter pivotà $ tableau caché de Post Modelprotected $hidden = ['pivot']
Sajjad Ashraf
C'est la meilleure solution (en supposant que vous utilisez une version assez moderne de Laravel)
Orrd
11

Une autre option consiste à utiliser la $hiddenpropriété du modèle pour masquer les colonnes que vous ne souhaitez pas afficher. Vous pouvez définir cette propriété à la volée ou définir des valeurs par défaut sur votre modèle.

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

Désormais, le mot de passe des utilisateurs sera masqué lorsque vous renvoyez la réponse JSON.

Vous pouvez également le configurer à la volée de la même manière.

User::$hidden = array('password');
Jason Lewis
la source
2
dans Laravel 4.2, j'obtiens «Impossible d'accéder à la propriété protégée User :: $ hidden» en essayant de définir cela dynamiquement.
mtmacdonald
1
ça ne devrait pas l'être static.
StackOverflowed le
@StackOverflowed, je suppose que vous n'avez pas remarqué l'âge de cette question / réponse et qu'elle était liée à Laravel 3.
Jason Lewis
10

Utilisation avec pagination

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

user2317976 a introduit une excellente façon statique de sélectionner les colonnes des tables associées.

Voici une astuce dynamique que j'ai trouvée pour que vous puissiez obtenir ce que vous voulez lorsque vous utilisez le modèle:

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

Je viens de trouver que cette astuce fonctionne également bien avec load (). Ceci est très pratique.

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

Assurez-vous d'inclure également la clé de la table cible, sinon elle ne pourra pas la trouver.

KinoP
la source
6

Par ici:

Post::with(array('user'=>function($query){
    $query->select('id','username');
}))->get();
Spécifications
la source
Veuillez toujours expliquer votre réponse.
Rohit Gupta
Eu un problème similaire, c'est le moyen le plus intelligent à ce jour! Cette réponse est sous-estimée!
eldblz
C'est la même chose que la réponse qui avait déjà été soumise précédemment par Sajjad Ashraf.
Orrd
5

Je sais que c'est une vieille question, mais si vous créez une API, comme le fait l'auteur de la question, utilisez des transformateurs de sortie pour effectuer de telles tâches.

Transofrmer est une couche entre le résultat réel de votre requête de base de données et un contrôleur. Il permet de contrôler et de modifier facilement ce qui va être envoyé à un utilisateur ou à un consommateur d'API.

Je recommande Fractal comme base solide de votre couche de transformation de sortie. Vous pouvez lire la documentation ici .

Armen Markossyan
la source
4

Sur Laravel 5.5, le moyen le plus propre de le faire est:

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

Vous ajoutez deux points et les champs que vous souhaitez sélectionner séparés par une virgule et sans espace entre eux.

JoeGalind
la source
Savez-vous comment pouvons-nous récupérer une colonne spécifique de la table associée lors de l'utilisation de la pagination.
Daniyal Nasir
2

Utilisation du modèle:

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

Utilisation de Query Builder:

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

Si j'ai bien compris, ce qui est renvoyé est bien sauf que vous ne voulez voir qu'une seule colonne. Si tel est le cas, cela devrait être beaucoup plus simple:

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