Laravel 8 中实现跨关联表的多条件模糊搜索(含主表与子表字段)

14次阅读

Laravel 8 中实现跨关联表的多条件模糊搜索(含主表与子表字段)

laravel 8 中,可通过 `wherehas()` 结合闭包查询,在保持原有 eloquent 关系链的同时,对关联模型(如 `stock`、`category` 等)的字段进行 like 模糊搜索,无需破坏原有查询结构。

你当前的查询仅在主表 terms 的 title 字段中搜索关键词,但实际业务中常需支持“跨表搜索”——例如同时匹配商品标题(term.title)、库存编码(stock.code)、分类名称(category.name)或属性值(attributes.value)。laravel 提供了优雅的解决方案:whereHas(),它允许你在已定义的 Eloquent 关系基础上,对关联模型执行条件查询。

以下是以你代码为基础的完整优化示例(假设关系已正确定义):

$posts = Term::where('user_id', $user_id)     ->where('status', 1)     ->where('type', 'product')     ->with(['preview', 'attributes', 'category', 'price', 'options', 'stock', 'affiliate'])     ->withCount('reviews');  // 若存在搜索关键词,则启用跨表模糊搜索 if (!empty($request->term)) {     $term = '%' . $request->term . '%';      $posts = $posts->where(function ($query) use ($term) {         // 主表字段搜索         $query->where('title', 'LIKE', $term)               ->orWhereHas('stock', function ($q) use ($term) {                   $q->where('code', 'LIKE', $term);               })               ->orWhereHas('category', function ($q) use ($term) {                   $q->where('name', 'LIKE', $term);               })               ->orWhereHas('attributes', function ($q) use ($term) {                   $q->where('value', 'LIKE', $term); // 假设 attributes 是一对多,且含 value 字段               });     }); }  $data = $posts->get(); // 执行最终查询

关键说明:

  • whereHas(‘stock’, …) 要求模型 Term 必须已定义 stock() 关系方法(如 return $this->hasOne(Stock::class, ‘term_id’););
  • 使用外层 where(function () {…}) 包裹所有 OR 条件,避免逻辑优先级错误(否则 WHERE status=1 AND type=’product’ OR … 会破坏原有筛选);
  • 若需搜索多个字段(如 stock.code 和 stock.barcode),可在 whereHas 的闭包内叠加 orWhere;
  • 对于一对多关联(如 attributes),whereHas 默认按「至少一条匹配」生效;若需「全部匹配」,应使用 wheredoesntHave() 或子查询配合 havingRaw,但属进阶场景。

⚠️ 注意事项:

  • 数据库索引至关重要:为高频搜索字段(如 term.title、stock.code、category.name)添加 INDEX,否则模糊查询(LIKE ‘%xxx%’)将导致全表扫描,性能急剧下降;
  • 避免在 whereHas 中嵌套过深或多层 orWhereHas,可能引发 N+1 或笛卡尔积风险,建议结合 with() 预加载并用 php 层二次过滤(适用于数据量小的场景);
  • 如需全文检索能力(如中文分词、相关性排序),应考虑 mysql FULLTEXT 索引或集成 Algolia / Meilisearch。

通过 whereHas(),你无需拆分查询、无需原生 SQL,即可在 Laravel 的 Eloquent 生态中安全、可维护地实现多表联合搜索——这才是符合 Laravel 哲学的优雅解法。

text=ZqhQzanResources