Laravel嵌套Eloquent关联查询pluck提取字段报错问题
Eloquent关联查询指定字段(适配Maatwebsite Excel导出场景)
问题说明
执行查询后返回的Result模型集合包含嵌套的Touchpoint多态关联,原有查询代码如下:
$result = Result::query()->where('audit_id', 1)->where('result_type', 'App\Models\Touchpoint')->whereIn('result_id', $tps)->with('result')->get();
返回结构示例:
Illuminate\Database\Eloquent\Collection {#5145 all: [ App\Models\Result {#5207 id: 198, result_id: 30, result_type: "App\Models\Touchpoint", audit_id: 1, weight: 7, pics: 0, recs: 0, rating: 4, comments: "none", complete: 1, created_at: "2022-06-03 03:42:24",updated_at: "2022-06-03 03:42:24", result: App\Models\Touchpoint {#5210 id: 30, name: "Lineman", description: "The location food offer was available on Lineman", sort_order: 25, req_pics: 0, req_recs: 0, sector_id: 1, created_at: null, updated_at: "2022-04-02 14:02:34", }, }, App\Models\Result {#5119 id: 199, result_id: 29, result_type: "App\Models\Touchpoint", audit_id: 1, weight: 7, pics: 0, recs: 0, rating: 4, comments: "none", complete: 1, created_at: "2022-06-03 03:43:38", updated_at: "2022-06-03 03:43:38", result: App\Models\Touchpoint {#5206 id: 29, name: "Grab", description: "The location food offer was available on Grab", sort_order: 24, req_pics: 0, req_recs: 0, sector_id: 1, created_at: null, updated_at: "2022-04-02 14:02:26", }, }, ], }
需求是直接在查询构造阶段提取sort_order、name、description、rating、weight字段,不能对执行查询后返回的集合做二次处理,因为需要传入Maatwebsite\Excel\Concerns\WithMultipleSheets组件,该组件仅接收未执行的查询实例。之前尝试用pluck提取result.name这类嵌套关联字段时,系统提示result不存在。
报错原因
- 查询构造器阶段调用的
pluck()方法是直接生成SQL查询主表字段,不会识别模型定义的关联关系,自然无法读取嵌套的关联属性 - 如果是执行
get()拿到集合后再调用pluck('result.name'),虽然支持嵌套字段读取,但此时已经返回集合对象,不符合组件传参要求
实现方案
优先用Join联表查询,直接把需要的跨表字段查成平级结构,不需要处理嵌套关联,完全适配导出场景,且最终返回的是未执行的查询实例:
// 注意末尾不要调用get(),直接传查询实例给组件即可 $result = Result::query() ->where('audit_id', 1) ->where('result_type', \App\Models\Touchpoint::class) ->whereIn('result_id', $tps) // 关联touchpoints表,关联条件为result_id对应touchpoints主键id ->join('touchpoints', 'results.result_id', '=', 'touchpoints.id') // 直接指定需要查询的5个字段,跨表字段加表名前缀避免歧义 ->select( 'touchpoints.sort_order', 'touchpoints.name', 'touchpoints.description', 'results.rating', 'results.weight' );
如果后续还需要保留嵌套关联结构,只是要过滤多余字段,可以用预加载时指定关联字段的写法,注意主表必须包含多态关联依赖的result_id、result_type字段,关联表必须包含主键id,否则关联加载失败:
$result = Result::query() ->where('audit_id', 1) ->where('result_type', \App\Models\Touchpoint::class) ->whereIn('result_id', $tps) ->with(['result' => function ($query) { // 关联表只查需要的字段,必须带主键id $query->select('id', 'sort_order', 'name', 'description'); }]) // 主表只查需要的字段,必须带多态关联必需的result_id、result_type ->select('id', 'result_id', 'result_type', 'rating', 'weight');
这种写法返回的关联字段还是嵌套在result属性下,导出时需要额外做字段映射,不如Join方案直接。
内容的提问来源于stack exchange,提问作者Aaron Harker
相关产品推荐
相关产品推荐

