Laravel多表搜索:合并产品与用户类型关联的查询结果
Laravel搜索结果合并方案
最优解:单数据库查询实现(推荐)
直接通过关联查询和条件分组,一次数据库查询就能获取所有符合要求的激活产品,避免多次查询和集合合并,效率更高。
代码实现
use Illuminate\Database\Eloquent\Builder; $products = Product::query() // 先限定产品状态为Active ->where('status', 'Active') // 分组处理所有匹配条件(产品自身匹配 OR 用户类型匹配) ->where(function (Builder $query) use ($search, $search_any) { // 产品名称匹配 $query->where('name', 'LIKE', "%{$search}%") // 产品slug匹配 ->orWhere('slug', 'LIKE', "%{$search_any}%") // 关联用户的type字段匹配,返回该用户的所有激活产品 ->orWhereHas('user', function (Builder $userQuery) use ($search_any) { $userQuery->where('type', 'LIKE', "%{$search_any}%"); }); }) ->get();
逻辑说明
- 外层的
where('status', 'Active')确保所有返回的产品都是激活状态; - 内层闭包通过
orWhere整合三个匹配规则:产品名称匹配、产品slug匹配、用户类型匹配; whereHas方法利用产品与用户的关联关系,直接筛选出归属符合type条件用户的产品。
备选方案:集合合并(适合需分开处理查询的场景)
如果必须分开执行两次查询,再合并结果,可以使用Laravel集合的merge方法,同时注意去重(避免同一产品因满足多个条件重复出现)。
代码实现
// 查询1:名称/slug匹配的激活产品 $products = Product::query() ->where(function ($query) use ($search, $search_any) { $query->where('name', 'LIKE', "%{$search}%") ->orWhere('slug', 'LIKE', "%{$search_any}%"); }) ->where('status', 'Active') ->get(); // 查询2:用户type匹配的用户发布的激活产品 $productNew = Product::query() ->whereHas('user', function ($userQuery) use ($search_any) { $userQuery->where('type', 'LIKE', "%{$search_any}%"); }) ->where('status', 'Active') ->get(); // 合并两个集合并按ID去重 $mergedProducts = $products->merge($productNew)->unique('id');
注意事项
unique('id')必须添加,否则同一产品若同时满足两个查询条件,会在结果中重复出现;- 这种方式会执行两次数据库查询,性能略低于单查询方案。
安全优化建议
直接拼接%{$search}%存在SQL注入风险,建议使用Laravel的参数绑定写法,示例:
// 替换直接拼接的写法 ->where('name', 'LIKE', DB::raw('concat("%", ?, "%")'), [$search])
内容的提问来源于stack exchange,提问作者user3653474
相关产品推荐
相关产品推荐

