Laravel 在 with 查询中只查询个别字段

刚答了一篇帖子, 算比较常用的技巧,整理一下分享出来。

在使用 Laravel 的关联查询中,我们经常使用 with 方法来避免 N+1 查询,但是 with 会将目标关联的所有字段全部查询出来,对于有强迫症的我们来说,当然是不允许的。

这时候我们可以使用下面的技巧在使用 with 时只查询目标关联的部分字段:

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

但是每次查询都写得这么繁琐真的好么?不如利用 Laravel 的范围查询将其封装起来:

在 Model 基类中定义一个范围查询(或者使用 Trait)

class BaseModel extends \Eloquent{
    public function scopeWithOnly($query, $relation, Array $columns)
    {
        return $query->with([$relation => function ($query) use ($columns){
            $query->select(array_merge(['id'], $columns));
        }]);
    }
}

在我们普通的 Model 类都继承基类:

class Topic extends BaseModel{
    public function user()
    {
        return $this->belongsTo('User');
    }
}

然后使用就很方便了:

$topics = Topic::limit(2)->withOnly('user', ['username'])->get();
本帖已被设为精华帖!
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 25

如果关联关系是多层嵌套需要怎么才能实现,例如 ...->with('product.productImg')->get()

3年前 评论
小怪兽

就是会不会感觉有点多余,因为我感觉你这样在查的时候也是把要查的字段以数组形式放进去 跟外面写貌似都一样的性质,还是说我理解错了呢

3年前 评论

@ruanqi with查询结果空是因为你的查询字段不包含你的关联字段, 就比如 拿ID关联的话, 你就得 select() 里必须包含ID, 要么就返回空

2年前 评论

@2016 为啥没有包含关联字段就会为空呢,文档上没找到说明

2年前 评论

我想问下 为什么我 的是为空呢 ?
$faqs = Faq::limit(5)
->withOnly('reply', ['id', 'content'])
->get();

1年前 评论

是按你说那样在baseModel 中添加了你的那个方法

1年前 评论

我直接用with 时查询了所有

1年前 评论

我也觉得多余了。
不过可能安全性能好点?比如缺省某些字段。

我改写了一下,因为我主键名不为 id,所以楼主那样就会 null 了。

    public function scopeWithOnly(object $query, string $relation, array $columns)
    {
        return $query->with([$relation => function ($query) use ($columns) {

            if (count($columns) == 1) {
                $columns = array_merge(['id'], $columns);
            }
            $query->select($columns);
        }]);
    }
7个月前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!