Filtering Laravel API to show only categories with associated posts

Hey everyone. I’m working on a Laravel API and I’ve hit a snag. Right now my API shows all categories whether they have posts or not. But I want to change it so it only shows categories that actually have posts attached to them.

I’ve got my CategoryResource and CategoryController set up but I’m not sure how to add this filter. Here’s what I’m trying to do:

  1. Only get categories that have at least one post
  2. Don’t show any categories without posts

My current code looks something like this:

class CategoryResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            // other fields...
            'posts' => PostResource::collection($this->whenLoaded('posts')),
        ];
    }
}

class CategoryController extends Controller
{
    public function index() {
        $categories = CategoryResource::collection(Category::where('status', '1')->with('posts')->orderby('id', 'desc')->get());
        return response()->json($categories);
    }
}

Can anyone help me figure out how to add this filter to my controller? Thanks in advance!

I’ve faced a similar issue in one of my projects. What worked for me was using the whereHas() method in the query. It’s a bit more flexible than just has(). Here’s how you could modify your controller:

public function index() {
$categories = Category::where(‘status’, ‘1’)
->whereHas(‘posts’, function ($query) {
$query->where(‘status’, ‘published’);
})
->with(‘posts’)
->orderBy(‘id’, ‘desc’)
->get();

return CategoryResource::collection($categories);

}

This approach not only filters categories with posts but also allows you to add conditions to those posts. In this example, I’m assuming you might want only published posts. You can adjust the inner query as needed.

Also, don’t forget to eager load the posts to avoid N+1 query issues. The with(‘posts’) takes care of that. Hope this helps!

hey there, i think i can help u out. try adding ->has(‘posts’) to ur query in the controller. it’ll filter out categories without posts. like this:

$categories = Category::where(‘status’, ‘1’)->has(‘posts’)->with(‘posts’)->orderBy(‘id’, ‘desc’)->get();

that should do the trick for ya!

To filter categories with associated posts, you can modify your CategoryController’s index method. Here’s how you can achieve this:

public function index() {
    $categories = Category::where('status', '1')
        ->has('posts')
        ->with('posts')
        ->orderBy('id', 'desc')
        ->get();

    return CategoryResource::collection($categories);
}

The key here is using the has('posts') method. This ensures that only categories with at least one associated post are retrieved. This approach is more efficient as it performs the filtering at the database level, reducing the amount of data transferred and processed.

Remember to adjust your CategoryResource if needed to handle the case where posts might not be loaded. This solution should give you exactly what you’re looking for - categories with posts, ordered by ID descending.