Laravel Eloquent - 使用过滤数据获取嵌套关系

Posted

技术标签:

【中文标题】Laravel Eloquent - 使用过滤数据获取嵌套关系【英文标题】:Laravel Eloquent - Get nested relationships with filtered data 【发布时间】:2022-01-03 04:36:17 【问题描述】:

假设我有以下模型:

类别-(hasMany/belongsTo)-子类别-(hasMany/belongsTo)-产品

这些模型在前端创建一个可折叠的产品列表,如下所示:

Category1
  - Subcategory1
    - Product1
    - Product2
Category2
  - SubCategory3
    - Product4

现在,我想搜索 Product1 并检索它,同时保持关系 Category->Subcategory->Product 不变,这样我就可以像这样轻松地打印出来:

Category1
 - Subcategory1
  - Product1

我知道,通过以下查询,您可以搜索具有特定条件的产品的所有类别:

<?php
    $Categories = Categories::whereHas('subcategories', function ($q) use ($request) 
        $q->whereHas('products', function ($q) use ($request) 
            $q->where('name', 'LIKE', "%$request->search%")
              ->orWhere('article_number', 'LIKE', "%$request->search%");
        );
    )
    ->get();
?>

但这只会返回类别。

然后我打算将它们变成具有以下资源类的集合,在我了解到实际上我只从上面的查询中获取类别之前:

$Collection = CategoriesResource::collection($Categories);

//------------------------------------------------

class CategoriesResource extends JsonResource

    public function toArray($request)
    
        return [
            'id' => $this->id,
            'name' => $this->name,
            'subcategories' => $this->subcategories()->with('products')->get(),
        ];
    

我的问题是,我是否可以预先使用不同的查询,或者将条件传递给 with 语句,这样我只会得到满足搜索条件的产品?理想情况下,我希望数据集中没有空的类别或子类别,但如果无法管理,也可以。

我也尝试了反向,直接搜索products,得到属于belongsTo关系的category,但是我不知道有一种可行的方法将Product->Categories反转回Categories->Products。


编辑: OMR 的解决方案帮助了我,但我不得不添加另一个 whereHas-query 以过滤掉空的子类别。

    $Categories = Categories::whereHas('subcategories', function ($q) use ($request) 
        $q->whereHas('products', function ($q) use ($request) 
            $q->where('name', 'LIKE', "%$request->search%")
                ->orWhere('article_number', 'LIKE', "%$request->search%");
        );
    )->with(['subcategories'=> function ($q) use ($request) 
        $q->whereHas('products', function ($q) use($request) 
            $q->where('name', 'LIKE', "%$request->search%")
                ->orWhere('article_number', 'LIKE', "%$request->search%");
        )->with(['products'=>function ($q) use ($request) 
            $q->where('name', 'LIKE', "%$request->search%")
                ->orWhere('article_number', 'LIKE', "%$request->search%");
        ]);
    ])->get();

【问题讨论】:

【参考方案1】:

您可以在急切加载时重复相同的条件:

  $Categories = Categories::whereHas('subcategories', function ($q) use ($request) 
        $q->whereHas('products', function ($q) use ($request) 
            $q->where('name', 'LIKE', "%$request->search%")
                ->orWhere('article_number', 'LIKE', "%$request->search%");
        );
    )->with(['subcategories'=> function ($q) use ($request) 
        $q->with(['products'=>function ($q) use ($request) 
            $q->where('name', 'LIKE', "%$request->search%")
                ->orWhere('article_number', 'LIKE', "%$request->search%");
        ]);
    ])->get();

【讨论】:

非常感谢,这个解决方案帮助了我。实现之后,我只需要用 whereHas 重复条件来过滤掉空的子类别就可以完美了。

以上是关于Laravel Eloquent - 使用过滤数据获取嵌套关系的主要内容,如果未能解决你的问题,请参考以下文章

Lumen/Laravel Eloquent - 按数据透视表中的属性过滤

从 eloquent builder laravel 7 获取关系数据

Laravel cviebrock/eloquent-sluggable 将 @ 作为前缀或在路由中过滤它

在 Laravel Eloquent 中获取和过滤关系

如何在 Laravel Eloquent 上过滤相关模型

Laravel 5 - Eloquent:过滤多种关系的简单方法