请教“查询已存在的关联”进行过滤并同时输出过滤后的和“不存在的关联”

运行环境

  • CentOS Stream 9
  • PHP 8.1.9
  • Laravel v9.37.0

问题场景

一个 SNS 系统,涉及用户、屏蔽、帖子三个维度。在查询帖子时,希望过滤掉所属用户屏蔽话题的帖子。

模型

<?php

namespace App\Models;

class Post extends Model
{
    public function hashtags()
    {
        return $this->belongsToMany(Hashtag::class, 'hashtag_usages', 'usage_id', 'hashtag_id')->wherePivot('usage_type', HashtagUsage::TYPE_POST)->wherePivot('deleted_at', null);
    }
}
  • posts 帖子表
  • hashtags 话题表
  • hashtag_usages 话题和帖子中间关联表(多对多,一个帖子有多个话题,一个话题也会有多个帖子)

问题

$postQuery = Post::with(['hashtags'])->latest();

// 用户屏蔽话题
$blockHashtagIds = [1,5,10]

if ($blockHashtagIds) {
    $postQuery->whereHas('hashtags', function ($query) use ($blockHashtagIds) {
        // 含有用户屏蔽话题的帖子不要
        $query->whereNotIn('hashtag_id', $blockHashtagIds);
    });
}

$posts = $postQuery->paginate(\request()->get('pageSize', 15));

使用whereHas方法,模型只给我含有话题的帖子用于条件筛选,这样输出时不含话题的帖子也被过滤了。

问题原理:

  • 你要过滤话题了,那我(框架)就只给你含有话题的帖子让你过滤,然后过滤后输出的就只有含话题的,因为不含话题的框架没有给我。
  • 你要过滤小组了,那我(框架)就只给你含有小组的帖子让你过滤,小组 id 字段为 null 也不给你,因为你要过滤的 whereNotIn 是小组 id,它没有 id,所以不会在数据里(如果字段值为 0 我框架就给你数据,因为 0 也算是有小组的)。

求教

求教大神们,我应该如何实现,过滤掉含有屏蔽话题的帖子,其余(包括不含话题的帖子)都输出呢?

jevan
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

whereHas改成whereDoesntHave试试,并且whereNotIn改成whereIn

2年前 评论

应该是有两种方法实现的:

  1. 和一楼一样,使用 whereDoesntHave

    $postQuery->whereDoesntHave('hashtags', function ($query) use ($blockHashtagIds) {
         // 含有用户屏蔽话题的帖子
         $query->whereIn('hashtag_id', $blockHashtagIds);
     });
  2. 还是使用 whereHas

    $postQuery->whereHas('hashtags', function ($query) use ($blockHashtagIds) {
         // 含有用户屏蔽话题的帖子
         $query->whereIn('hashtag_id', $blockHashtagIds);
     }, '=', 0);
2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!