使用 laravel 雄辩中的 “with()” 函数获取特定列


Get Specific Columns Using “With()” Function in Laravel Eloquent

>我有两个表,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()的特定列。我该怎么做?

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

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

它只会从其他表中选择idusername。我希望这将帮助其他人。

<小时 />

请记住,主键(在本例中为 id)必须是 $query->select()实际检索必要的结果.*

从 Laravel 5.5 开始,你可以这样做:

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

注意id字段和foreign keys,如文档中所述:

使用此功能时,应始终包含 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将为空。

对于加载具有特定列的模型,尽管不是预先加载,您可以:

在您的Post模型中

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

原始功劳归于Laravel急切加载 - 仅加载特定列

当走另一条路(hasMany)时:

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

不要忘记包含外键(假设在此示例中user_id外键)来解析关系,否则您的关系将得到零结果。

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

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

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

如果你想在

laravel 雄辩中使用 with() 获得特定的列,那么你可以使用下面的代码,最初由 @Adam 在他的答案中回答同样的问题,答案的主要代码如下:

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

所以我在我的代码中使用它,但它给了我1052: Column 'id' in field list is ambiguous错误,所以如果你们也面临同样的问题

然后要解决它,您必须在方法中的 id 列之前指定表名with()如下代码

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

我遇到了这个问题,但有第二层相关对象。 @Awais Qarni 的答案在嵌套选择语句中包含适当的外键时成立。正如第一个嵌套选择语句中需要 id 来引用相关模型一样,外键也需要引用相关模型的二级;在此示例中为公司模型。

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

此外,如果要从 Post 模型中选择特定列,则需要在 select 语句中包含user_id列才能引用它。

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

Post模型中:

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

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

还有另一种替代方法,您可以急切加载特定列

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

请注意,如果您只需要表中的一列,那么使用"列表"非常好。就我而言,我正在检索用户最喜欢的文章,但我只想要文章 id:

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

返回一个 id 数组,例如:

Array
(
    [0] => 3
    [1] => 7
    [2] => 8
)

如果您使用 PHP 7.4 或更高版本,您也可以使用箭头函数执行此操作,使其看起来更干净:

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

我在使用我的用户模型(Laravel 8.x.x)的belongsToMany关系时遇到了同样的问题。

经过长时间的搜索和试用和测试方法。我找到了这个答案

您必须确保从该关系的任一端选择 id 和关系所需的任何外键。这使得Eloquent能够将父母与孩子相匹配。

原始功劳归 https://stackoverflow.com/a/64233242/1551102

所以我包括

Groups::select('groupid')
...

它就像一个魅力。虽然现在我想知道如何在获取后隐藏 groupid 字段。我知道我可以简单地遍历数组并删除它。但是还有其他方法吗?可能是一个更简单更好的。

您还可以在访问相关模型时指定相关模型上的列。

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

你可以试试这段代码。它在 laravel 6 版本中进行了测试。

控制器代码
 public function getSection(Request $request)
{
  Section::with(['sectionType' => function($q) {
      $q->select('id', 'name');
  }])->where('position',1)->orderBy('serial_no', 'asc')->get(['id','name','','description']);
  return response()->json($getSection);
}
型号代码
public function sectionType(){
    return $this->belongsTo(Section_Type::class, 'type_id');
}

请注意,如果不添加key列,它不会返回任何内容。如果只想显示username而不显示id,则可以改为在模型中定义$visible/$hidden属性,如下所示:

应用/模型/用户.php

protected $visible = ['username'];

然后它将仅检索username列:

Post::with('user')->get();

隐藏key列:

或者,您可以隐藏key列,然后仅检索所需的列。

应用/模型/用户.php

protected $hidden = ['id'];

指定您希望包含key的列,否则它不会返回任何内容,但这实际上只会返回用户名,因为id $hidden

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

现在,您可以在Collection实例上使用 pluck 方法:

这将仅返回Post modeluuid 属性

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

尝试使用条件。

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

因此,与其他解决方案类似,这是我的:

// For example you have this relation defined with "user()" method
public function user()
{
    return $this->belongsTo('User');
}
// Just make another one defined with "user_frontend()" method
public function user_frontend()
{
    return $this->belongsTo('User')->select(array('id', 'username'));
}
// Then use it later like this
$thing = new Thing();
$thing->with('user_frontend');
// This way, you get only id and username, 
// and if you want all fields you can do this
$thing = new Thing();
$thing->with('user');
<</div> div class="answers">

有时,在基于现有数据库(子集)创建小型应用程序时,让所有模型仅获取所需的字段可能很方便;即使通过with()加载也是如此。它可能会简化调试并避免混淆,举一个优点。"$visible"属性(如上所述)只能在模型转换为数组或 JSON 时使用;请参阅拉拉维尔文档。否则,可以使用本地作用域和"公共静态$fields"属性的组合,如下面的简化"用户类"示例所示。

class User extends Model
{
    public static $fields = [ 'id', 'full_name', 'image' ];
    
    public function scopeFields(Builder $query) : void {
        $query->select(self::$fields);
    }
    
    public function posts(): hasMany {
        return $this->hasMany(Post::class)->select(Post::$fields);
    }
}

让我们也使用著名的类 Post:

class Post extends Model
{
    public static $fields = [ 'id', 'user_id', 'text', 'created_at' ];
    
    public function scopeFields(Builder $query) : void {
        $query->select(self::$fields);
    }
    public function user(): HasOne {
        return $this->hasOne(User::class)->select(User::$fields);
    }
}

如您所见,函数 scopeFields 是相同的,因此您应该将其放在中间类中。无论如何,在此之后,您可以使用以下模型:

User::fields()->with('posts')->get();
Post::fields()->with('user')->get();

所有返回的对象将仅包含$fields中列出的属性。使用 Laravel 10 进行测试。

EmployeeGatePassStatus::with('user:id,name')->get();