使用rinvex/laravel-attributes获取指定EAV集合下的可用属性及对应值
基于Laravel EAV模型获取指定集合关联属性及可选值方案
核心思路
你使用的rinvex/laravel-attributes扩展包默认按属性类型分表存储值,我们可以通过联合查询所有值表的方式,直接从数据库层面过滤出目标Post集合用到的所有属性,再聚合得到每个属性的可选值,比遍历集合处理性能高很多。
实现代码
第一步:构造目标Post查询条件
不要直接调用get()拿到集合,复用查询条件先拿到目标Post的ID列表:
// 你的原始查询条件 $postQuery = Post::where('category_id', 2)->where('tag_id', 4); // 提取所有符合条件的Post主键ID $targetPostIds = $postQuery->pluck('id')->toArray();
第二步:查询属性及可选值
use Illuminate\Support\Facades\DB; // 扩展包默认支持的4种属性值类型 $attributeTypes = ['varchar', 'boolean', 'text', 'integer']; $availableFilters = collect($attributeTypes) ->flatMap(function ($type) use ($targetPostIds) { $valueTableName = "attribute_{$type}s"; return DB::table($valueTableName) // 关联属性元数据表 ->join('attributes', "{$valueTableName}.attribute_id", '=', 'attributes.id') // 只查目标Post关联的属性值 ->whereIn("{$valueTableName}.entity_id", $targetPostIds) ->select( 'attributes.id as attr_id', 'attributes.name as attr_name', 'attributes.slug as attr_slug', 'attributes.type as attr_type', "{$valueTableName}.content as attr_value" ) ->get(); }) // 按属性别名分组 ->groupBy('attr_slug') ->map(function ($valueGroup) { $baseAttr = $valueGroup->first(); return [ 'id' => $baseAttr->attr_id, 'name' => $baseAttr->attr_name, 'slug' => $baseAttr->attr_slug, 'type' => $baseAttr->attr_type, // 对值去重得到可选筛选值 'options' => $valueGroup->pluck('attr_value')->unique()->values() ]; }) ->values();
优化建议
- 各属性值表的
entity_id、attribute_id字段建议加联合索引,数据量大的时候查询性能提升明显 - 如果部分属性不需要展示在筛选栏,可以在关联
attributes表后加筛选条件,比如where('attributes.is_filterable', 1)过滤即可 - 返回的
$availableFilters可以直接传给前端渲染侧边栏筛选组件,每个属性的options就是对应可选值列表
内容的提问来源于stack exchange,提问作者M Mehdizadeh
相关产品推荐
相关产品推荐

