在Laravel Eloquent中使用"With()"函数获取特定的列

336

我有两个表,UserPost。一个User可以有多个posts,而一个post只属于一个user

在我的User模型中,我有一个hasMany关系...

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

在我的 post 模型中,我有一个 belongsTo 关系...

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

现在我想使用Eloquent with()连接这两个表,但是只想要第二个表中的特定列。我知道我可以使用查询构建器,但我不想使用。

当我在Post模型中编写...

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

它运行以下查询...

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

但是我想要的是...

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

当我使用...
Post::with('user')->get(array('columns'....));

它只返回第一个表的列。我想要使用with()从第二个表中获取特定的列。我该怎么做?

21个回答

563

我找到了解决方案。可以通过在 with() 中作为数组的第二个索引传递一个 闭包 函数来完成。

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

它只会从另一个表中选择idusername。我希望这能帮助其他人。


请记住,在$query->select()中,主键(在本例中为id)需要是第一个参数,以实际检索所需的结果。


5
很奇怪,我无法让这个工作。一旦我添加了 "$query->select('id','username');",就会收到 "Trying to get property of non-object" 的错误提示。 - user1669496
7
奇怪!仍然返回用户的所有字段。@AwaisQarni - justin
3
谢谢您分享这个信息。您是在哪里发现这个可能性的?我在 Laravel 文档中没有找到相关内容。 - Symen Timmermans
139
看到这条信息的人,请记住,在 $query->select() 中,需要包含主键(在本例中为 id),以实际检索所需的结果。我在我的代码中遗漏了这一点,因此无法找到任何结果,真是太傻了!希望这能帮助其他遇到同样问题的人。 - Azirius
11
好的,只需要添加外键,这里的外键是post_id,否则结果将为空。在这里提及外键非常重要。谢谢 :) - Hashaam Ahmed
显示剩余14条评论

288

自 Laravel 5.5 版本以来,您可以像这样实现:

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

根据文档,请注意 id 字段和任何相关的外键列都需要包含在您希望检索的列列表中。

使用此功能时,您应始终在要检索的列列表中包括 id 列和任何相关的外键列。

例如,如果用户属于团队并且具有team_id作为外键列,则如果您未指定 team_id,则$post->user->team为空。

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

此外,如果用户属于帖子(即在users表中存在post_id列),那么您需要像这样指定:

Post::with('user:id,username,post_id')->get();
否则$post->user将为空。

43
不要忘记包含外键(假设此处为post_id)以解析关系,否则您将得到关系的空结果。 - Hashaam Ahmed
5
这应该是被选中的答案。非常好用 :) - Graham
@Adam,这将限制子表中的列,我如何同时限制父表和子表中的列? - Sodium
1
@GauravGenius,你想要限制父级的所有内容都应该放在get()方法中。Post::with('user:id,username')->get(['age', 'color']); - Adam
1
@Imran_Developer,你的用户表主键是什么?也许Post::with('user:id,username')->get(['age', 'color', 'id']);可以用? - Adam
显示剩余7条评论

115

如果要加载特定列的模型,尽管不是急切加载,您可以:

在您的 Post 模型中

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

原始来源于Laravel Eager Loading - Load only specific columns


25
但是这种关系会使它像硬编码一样,无论什么情况下它都只会返回这两个字段。可能在其他情况下我需要更多的字段。 - Awais Qarni
然后你必须使用查询构建器。 - user1669496
7
这应该是被接受的答案。这是正确的做法。 - BugHunterUK
1
在Laravel 5.3版本中有没有一种方法可以做到这一点?我认为他们又改变了它...现在当我尝试使用这种方法时它返回null。 - Andre F.
有一段时间了,但你可以添加一个$fields参数。 - JordyvD
显示剩余4条评论

102

当采用反向关联(hasMany)时:

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

别忘了包含外键(假设在此示例中为 user_id)以解析关系,否则您将获得零个结果。


18
好的,确切地说,“不要忘记包括外键(假设在这个例子中它是user_id)”。 - aqingsao
你应该在选择字段中包括定义关系的列,例如user_id。 - alimfazeli
不错的发现,兄弟。 - Shahrukh Anwar
1
厉害了兄弟,外键的使用确实非常重要,幸亏我看到了你的答案,否则我就得愁眉苦脸地想了几个小时了。谢谢你! - Hashaam Ahmed
这段代码对我有用,谢谢。 - Khairul Islam Tonmoy
啊哈,我错过了那个重要的外键,现在这段代码可以工作了。 - Win

46

在 Laravel 5.7 中,您可以像这样调用特定字段

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

在选择中添加 foreign_key 字段非常重要。


21
请勿忘记添加外键字段。 - hendra1
5
不要忘记注意@hendra1的评论,除了主键之外,所有外键字段也是必需的,否则你将得到一个空的集合。这位朋友为我节省了时间,谢谢。 - Rajesh Vishnani

28

如果您想在laravel eloquent中使用with()获取特定列,则可以使用下面的代码,这是由@Adam在他的回答here中原始回答该问题的响应,答案的主要代码如下:

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

所以我在我的代码中使用了它,但是它给了我一个“1052: 列'id'在字段列表中不明确”的错误,所以如果你们也遇到同样的问题

那么为了解决它,你必须在with()方法中的id列之前指定表名,如下面的代码::

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

1
这对我来说返回了null,但我之前不知道这是可能的!好的,我过早地发布了,但我确实找到了一个结果。要使用这种方法(看起来更干净),您必须包括关系链接,例如在提取数据时的ID列。如果没有此限定符,则会返回null。 - Adsy2010
是的 @Adsy2010,要获取相关联的关系数据,您还必须获取id列或主键或负责该关系的任何id。 - Haritsinh Gohil
@Kamlesh Post::with('user:user.id,username')->get(); 这段代码将返回所有的帖子模型或表中的字段,以及来自“用户”表的仅包含idusername字段,但请注意,在使用with()函数之前,您应该在您的模型中拥有与相关表的关系,如果您没有关系,则可以使用查询构建器中的join - Haritsinh Gohil

25

我遇到了这个问题,但是涉及到第二层相关对象。@Awais Qarni的答案通过在嵌套选择语句中包含适当的外键来保持有效。就像第一个嵌套选择语句需要一个id来引用相关模型一样,在此示例中,需要外键来引用第二层相关模型;即公司模型。

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

此外,如果您想从“Post”模型中选择特定列,则需要在选择语句中包含“user_id”列以便引用它。

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

哇,太棒了@jwarshaw,这正是我在寻找的,这个“user_id”对我非常有用。 - Imran_Developer

16

在你的Post模型中:

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

现在,您可以使用$post->userWithName


3
真的吗?对我来说,这只是返回了空值,也就是说它出错了? - Sjwdavies
你值得拥抱! - Diego Favero
1
@Sjwdavies,你需要在选择语句中添加外键。 - S. Farooq

7

你还有另一个选择,可以预加载特定的列

public function show(Post $post)
{
    $posts = $post->has('user')->with('user:id,name,email,picture')->findOrFail($post->id);
    return view('your_blade_file_path',compact('posts);
}

在你的Post模型中,你应该也有一个user关系。
public function user()
{
    return $this->belongsTo( User::class, 'user_id')->withDefault();
}

注意:Laravel文档中提到了这一点。

https://laravel.com/docs/8.x/eloquent-relationships#eager-loading-specific-columns


你能帮我解决这个问题吗?它返回了产品名称,但没有“用户”对象:$product = Product::where('id', $p_id)->with('user:id,name')->get(['name']); - Imran_Developer
@Imran_Developer,因为你在get(['name'])中只返回了名称。请使用以下代码:$product = Product::with('user:id,name')->where('id', $p_id)->get(); - Neeraj Tangariya
是的亲爱的@Neeraj,但它返回了带有产品所有列的用户对象,而不是1或2个。但我已经通过使用以下代码解决了这个问题: $product = Product::with('user:id,name')->where('id', $p_id)->select('title', 'content', 'user_id')->get(); 在这里,“user_id”是重要的参考。 - Imran_Developer
@Imran_Developer 好的,非常好。 - Neeraj Tangariya

4
请注意,如果您只需要表中的一列,则使用“lists”非常好。在我的情况下,我正在检索用户喜爱的文章,但我只想要文章ID:
$favourites = $user->favourites->lists('id');

返回id数组,例如:
Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)

它返回一个集合! - Giovanni Far
如果你想要一个数组,那就调用 toArray() !!! $user->favourites->lists('id')->toArray(); - Giovanni Far
查询仍将获取其他列,因为list()方法只是更改结果数组,所以如果您只需要该表中的'id',则可能需要在查询中指定它。在执行查询时始终牢记性能是一个好习惯。享受编码! - ErvTheDev
-1 $user->favourites 将返回选择的所有字段的 Collection。正确的用法是:$user->favourites()->lists('id') - Wallace Vizerra
选择所有内容以后再使用PHP过滤是一个不好的想法。最好只在查询中使用所需的字段。了解Query\Builder::lists方法和Collection::lists方法之间的区别非常重要。 - Wallace Vizerra

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