Laravel 实体属性值过滤多个属性

Laravel Entity Attribute Value Filter Multipe Attributes

我正在尝试开发一个 post 模型,它与 post 元模型(包括 idpost_idmeta_key, meta_value 列)也和term model 有多对多的关系(包括term_id 和其他一些列,还有post_term table 包括idpost_postIdterm_term_term_id 列)。

我创建了一个表单,其中包含一些 post_metas 和搜索和过滤我的 post 的术语。

此示例 PHP 代码突出显示了我使用的内容:

$posts_query = Post::where('post_type', 'add')->where('author', Auth::id())->where(function ($q0) use($filter_metas){
            foreach ($filter_metas as $index => $meta) {
                $q0->whereHas('postmetas', function ($q0) use ($index,$meta) {
                    $q0->where('meta_key', $index)->where('meta_value', $meta);
                });
            }
        });

这是获取结果的执行查询。

select * from `posts` where `post_type` = ? and `author` = ? and (exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` in (?, ?, ?, ?)) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` in (?, ?, ?)) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` > ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?)

我可以从这个查询中得到正确的结果,但是查询执行得太慢,这是我的主要问题。是否有任何替代方法?

试试这个代码,不确定它是否有效,希望你能明白。

        $posts_query = Post::where('post_type', 'add')
        ->where('author', Auth::id())
        ->leftJoin('postmeta', function($join){
            $join->on('posts.postId', 'postmeta.post_id');
        })
        ->where(function ($query) use ($filter_metas) {
            foreach ($filter_metas as $index => $meta) {
                $query->where('postmeta.meta_key', $index)
                    ->where('postmeta.meta_value', $meta);
            }
        });

您可以使用带有聚合的单个连接查询来过滤每个 post

的元属性
$posts = Post::select(['posts.postId','posts.name'])
            ->where('post_type', 'add')
            ->where('author', Auth::id())
            ->join('postmeta', 'posts.postId', '=', 'postmeta.post_id')
            ->groupBy('posts.postId','posts.name')
            ->where(function ($query) use ($filter_metas) {
                foreach ($filter_metas as $index => $meta) {
                    $query->havingRaw('sum(case when meta_key = ? and meta_value = ? then 1 else 0 end) > 0', [$index, $meta]);
                }
            });

在上面的查询中havingRaw部分是关键它会条件性地过滤掉post与元信息不匹配的,