Home > front end >  Laravel query on Many to Many relationship
Laravel query on Many to Many relationship

Time:03-10

I have an API to keep tracked photos and tags. Each photo can have N tags and one tag can be linked to N photos. That's done using 3 tables:

  • Photo's table.
  • Tag's table.
  • photo_tag relation table.

Now I'm working to get all photos tagged with a set of tags the idea is to make requests to my API with a list of tags and get a list of photos that has at least all the tags.

I've been trying with the whereIn operator.

This is my code (now it's all hardcoded):

$photos = Photo::whereHas('tags', function (Builder $query) {
            $query->whereIn('tag', ['a5', 'mate', 'Brillante']);
        })->get();

        return response()->json($photos, 200);

When I execute it it return all that photos that match one tag and I need only photos that hast all the requested tags (in this example a5, mate).

I'm working on Laravel 9.

Edit:

As Tim Lewis suggested I've tried looping:

$tags = array("a5", "mate", "Brilante");
        $photoQuery = Photo::query();

        foreach($tags as $tag) {
            \Log::debug($tag);
            $photoQuery->whereHas('tags', function($query) use ($tag) {
                return $query->where('tag', $tag);
            });
        }

        $photos = $photoQuery->get();

Now it's returning an empty list I think because is looking for Photos that only have the 3 tags I hardcoded on the array.

Edit 2:

It seems that those changes were right, but for some reason Postman was not showing me any results of those changes are the solutions to my issue.

CodePudding user response:

Since the whereIn() method matches against any of the values provided, and not all, you'll need to modify this. Specificying a number of whereHas() clauses, 1 for each Tag, should work:

$photoQuery = Photo::query();
foreach ($request->input('tags') as $tag) {
  $photoQuery = $photoQuery->whereHas('tags', function ($query) use ($tag) {
    return $query->where('tag', $tag);
  });
}
$photos = $photoQuery->get();

Now, depending on the tags being sent to your API (assuming through the $request variable as a 'tags' => [] array), this query will include a whereHas() clause for each Tag, and only return Photo records that have all specified Tags.

  • Related