Laravel (8.x) 这个多对多过滤问题有更好的 Eloquent 查询吗?

Posted

技术标签:

【中文标题】Laravel (8.x) 这个多对多过滤问题有更好的 Eloquent 查询吗?【英文标题】:Laravel (8.x) Is there a better Eloquent query for this many-to-many filtering problem? 【发布时间】:2021-06-16 05:53:15 【问题描述】:

我有什么

movies多对多stars

movies多对多tags

studio一对多movies

我将studio 名称、star 名称和/或tag 名称作为可选查询字符串传递

我需要什么

如果所有 3 个都作为参数传递,则选择所有 moviestagstarstudio 选择所有moviestagstar(如果这两个作为参数传递) 如果 moviesstarstudio 作为参数传递,则选择所有 movies 如果moviestagstudio 作为参数传递,则选择所有movies 选择所有moviestagstarstudio(如果有任何一个作为参数传递) 基本上,简化此查询

我可能很愚蠢的代码

public function index(Request $request)
    

        $movies = Movie::with('stars')->with('tags')->with('studio');

        // all matches
        // if all params are present
        if ($request->star && $request->tag && $request->studio)
            $movies->whereHas('stars', function ($query) use ($request) 
                $query->where('name', $request->star);
            )->whereHas('tags', function ($query) use ($request) 
                $query->where('name', $request->tag);
            )->whereHas('studio', function ($query) use ($request) 
                $query->where('name', $request->studio);
            );

        // star and tag with no studio
        if ($request->star && $request->tag && !$request->studio)
            $movies->whereHas('stars', function ($query) use ($request) 
                $query->where('name', $request->star);
            )->whereHas('tags', function ($query) use ($request) 
                $query->where('name', $request->tag);
            );

        // star and studio with no tag
        if ($request->star && !$request->tag && $request->studio)
            $movies->whereHas('stars', function ($query) use ($request) 
                $query->where('name', $request->star);
            )->whereHas('studio', function ($query) use ($request) 
                $query->where('name', $request->studio);
            );

        // studio and tag with no star
        if (!$request->star && $request->tag && $request->studio)
            $movies->whereHas('tags', function ($query) use ($request) 
                $query->where('name', $request->tag);
            )->whereHas('studio', function ($query) use ($request) 
                $query->where('name', $request->studio);
            );

        // any one matches
        if ($request->star || $request->tag || $request->studio)
            $movies->whereHas('stars', function ($query) use ($request) 
                $query->where('name', $request->star);
            )->orWhereHas('tags', function ($query) use ($request) 
                $query->where('name', $request->tag);
            )->orWhereHas('studio', function ($query) use ($request) 
                $query->where('name', $request->studio);
            );

        return response($movies->paginate(20));
    

【问题讨论】:

【参考方案1】:

我想你需要的是这样的:

public function index(Request $request)


    $movies = Movie::with('stars')->with('tags')->with('studio');

    // all matches
    // tag
    if ($request->tag)
        $movies->whereHas('tags', function ($query) use ($request) 
            $query->where('name', $request->tag);
        );

    // star
    if ($request->star)
        $movies->whereHas('stars', function ($query) use ($request) 
            $query->where('name', $request->star);
        );
    // studio
    if ($request->studio)
        $movies->whereHas('studio', function ($query) use ($request) 
            $query->where('name', $request->studio);
        );

    return response($movies->paginate(20));

这样你只过滤你的关系,如果它提供了它的键。

【讨论】:

啊,这是我最初的方法,然后我把事情复杂化了,谢谢伙计,这行得通。这是方法。但在演播室里也应该是whereHas 而不是orWhereHas,对吧? Np :) 是的,它应该是whereHas。我已经修好了谢谢:)

以上是关于Laravel (8.x) 这个多对多过滤问题有更好的 Eloquent 查询吗?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4.1 多对多关系和条件在哪里?

Laravel:具有 whereHas 和多对多关系的全局范围

从父多对多关系获取所有子模型 Laravel Eloquent

刀片模板中的多对多关系中的 Laravel 嵌套查询

Laravel 上的多对多问题关系

Laravel 8 多对多更改自定义属性的 id