在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个回答

3
如果您使用的是PHP 7.4或更高版本,则可以使用箭头函数来使代码看起来更简洁:
Post::with(['user' => fn ($query) => $query->select('id','username')])->get();

2

在使用Laravel 8.x.x中的belongsToMany关系时,我遇到了同样的问题。

经过长时间的搜索和试验,我找到了这个答案:

您必须确保从该关系的任一侧选择id和任何所需的外键,这允许Eloquent将父项与其子项匹配。

原始信用归功于https://stackoverflow.com/a/64233242/1551102

因此,我包含了:

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

它像魔法一样奏效。不过现在我想知道如何在获取后隐藏groupid字段。 我知道我可以简单地遍历数组并将其删除。但是否有其他方法?可能更简单,更好的方法。


哦,谢谢兄弟 :) ,你真的真的节省了我的时间。 - Waleed Khaled

1
你可以尝试这段代码。它在 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');
}

1

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

app/Models/User.php

protected $visible = ['username'];

然后它将仅检索带有 username 列的内容:
Post::with('user')->get();

隐藏key列:

或者,您可以隐藏key列,然后只检索您想要的列。

app/Models/User.php

protected $hidden = ['id'];

指定要包含的列,包括key,否则它将不返回任何内容,但实际上这只会返回用户名,因为id$hidden
Post::with('user:id,username')->get();

1
你可以在访问相关模型时指定列。

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


0

尝试使用条件。

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

0

所以,与其他解决方案类似,这是我的:

// 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');

0
现在您可以在Collection实例上使用pluck方法:
这将仅返回Post模型uuid属性。
App\Models\User::find(2)->posts->pluck('uuid')
=> Illuminate\Support\Collection {#983
     all: [
       "1",
       "2",
       "3",
     ],
   }

0
有时候,在基于(现有数据库的子集)创建小型应用程序时,当加载通过with()方法时,使所有模型只获取所需字段可能会很方便;这样可以简化调试、避免混淆,以及提供其他优势。 上述提到的'$visible'属性只能在将模型转换为数组或JSON时使用;请参阅Laravel文档。否则,您可以使用本地作用域和静态属性'public static $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中进行了测试。

0
所以这是我的旧代码,它运行良好,但不如预期。
$query = Book::withCount('bookReviews')
            ->withAvg('bookReviews', 'rating')
            ->with('createdBy:id,name')
            ->orderBy($sortField, $sortOrder);

意思是我得到了这样的结果
..................
{
    "id": 31,
    .....
    "created_by": {
        "id": 12,
        "name": "Darwin Grady"
    },
    .....
},
..................

但我只想获取由用户创建的名称,所以我不得不将其更改为
$query = Book::withCount('bookReviews')
            ->withAvg('bookReviews', 'rating')
            ->addSelect(['createdBy' => User::select('name')->whereColumn('id', 'books.created_by')])
            ->orderBy($sortField, $sortOrder);

现在这就是预期的结果
..................
{
    "id": 31,
    .........
    "createdBy": "Darwin Grady"
},
..................

看看这个:高级子查询

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