Laravel Eloquent: 如何仅从关联表中获取特定列?

108

我在Eloquent中有两个连接的表,分别是主题和用户。

主题模型:

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

用户模型:

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

我的Eloquent api调用如下:

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

使用如下代码可仅从用户模型中获取“username”列:
``` Theme.objects.values('user__username') ```
需要注意的是,“user”是外键字段名,应该根据具体情况进行调整。

我正在处理类似的任务,我想知道如果我使用“Response”,我需要导入哪种类? - Agnes Palit
16个回答

105

更改您的模型以指定要选择哪些列:

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

同时不要忘记包含你加入的列。


6
非常好的答案,而且关于包含连接列的提示节省了我大量的时间! - greatwitenorth
如果有些地方我只需要ID而不是ID和用户名,那么我还需要选择两者吗? - Dariux
嗨,选择函数在模型查询构建器中是否具有相同的功能? - Gokigooooks
5
我不认为这是一个好的方法。这将会硬编码列名。所有地方都只会返回这些列。在其他一些API中,我可能需要更多的列,所以这里行不通。我认为使用查询构建器是解决方法。 - Aman Sura
3
这是一种戏剧化的方法,因为每次您往后打电话时都会发生。我相信Sajjad Ashraf的答案是大多数人会感兴趣的。 - MMMTroy

36

适用于 Laravel >= 5.2

使用->pluck()方法。

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

如果您想要检索包含单列值的数组,您可以使用pluck方法。


对于 Laravel <= 5.1

请使用->lists()方法。

$roles = DB::table('roles')->lists('title');
该方法将返回一个角色标题的数组。您还可以为返回的数组指定自定义的键列:

2
这并不是问题的答案(该问题特别涉及连接/关系)。 - orrd

33

您可以在get参数中提供一个字段数组,如下所示:

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

更新(适用于 Laravel 5.2) 从文档中,您可以这样做:

$response = DB::table('themes')
    ->select('themes.*', 'users.username')
    ->join('users', 'users.id', '=', 'themes.user_id')
    ->get();

3
我尝试了这个操作,但出现了错误“SQLSTATE [42S22]:找不到列”,它的SQL语句中没有包括“with”子句中的表。在错误信息中出现的SQL语句是“SELECT fk_table.column1 FROM main_table”。 - Michel Ayres
1
这里应该是 "users.username" 而不是 "user.username"。如果你的表和列名与实际数据库匹配,答案中的代码将会起作用。这种解决方案的缺点在于它构建了一个 SQL 查询而不是使用 Eloquent,所以名称必须与实际数据库表和列匹配。 - orrd

27

我知道你想要使用Eloquent,但你可以使用Fluent Query Builder来完成同样的功能。

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

17

这就是我做事的方式

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

用户2317976的第一个答案对我不起作用,我正在使用laravel 5.1


2
最新的答案 = 有用的! - thesunneversets
谢谢。对我来说很好用。我必须像你在'id'中那样在选择语句中添加外键,否则它会返回null。 - Iman Sedighi
1
@mayid 你可以尝试将 pivot 添加到 Post 模型的 $hidden 数组中 protected $hidden = ['pivot'] - Sajjad Ashraf
这是最佳解决方案(假设您正在使用相当现代的Laravel版本) - orrd
这对我有用,即使使用通配符 ->join('products','products.id','id)->select('stock.*','product.name') - Nigel Atkinson
显示剩余2条评论

13

使用分页功能

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

11

另一种选择是利用模型上的$hidden属性来隐藏您不想显示的列。您可以即时定义此属性,也可以在模型上设置默认值。

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

现在,当您返回JSON响应时,用户的密码将被隐藏。

您还可以以类似的方式即时设置它。

User::$hidden = array('password');

2
在 Laravel 4.2 中,当我尝试动态设置此属性时,出现“无法访问受保护的属性User::$hidden”的错误。 - mtmacdonald
1
它不应该是“静态的”。 - StackOverflowed
@StackOverflowed,我猜你没有注意到这个问题/答案的年代以及它与Laravel 3有关。 - Jason Lewis

6

这样做:

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

请始终解释您的答案。 - Rohit Gupta
遇到了类似的问题,这是目前最聪明的解决方法!这个答案被低估了! - eldblz
这与之前由Sajjad Ashraf提交的答案相同。 - orrd

6

user2317976提供了一种很好的静态方法来选择相关表的列。

这里是我发现的一种动态技巧,让你在使用模型时可以得到你想要的任何内容:

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

我刚发现这个技巧在使用load()时也非常有效。这非常方便。

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

请确保您还包括目标表的键,否则它将无法找到。


5
我知道这是一个老问题,但如果您正在构建API,就像问题的作者一样,请使用输出转换器来执行此类任务。
转换器是实际数据库查询结果和控制器之间的一层。它允许轻松控制和修改将要输出给用户或API消费者的内容。
我建议使用Fractal作为输出转换层的可靠基础。您可以在这里阅读文档。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接