I\'m developing an application that lists images, and has multiple tags assigned to each image. I\'d like to be able to find the images that are tagged with all
Looking for images that has all the tags, we will probably need to count our results and group by the image_url after making our necessary joins. This way, we can see how many tags each image matches and just get the images that match all the tags using the count because we know how many tags we have.
$tags = explode(' ', $tag_text);
$images = DB::table('images')
->select(DB::raw('COUNT(*) AS `TheCount`, images.download_url'))
->join('image_tag', 'images.id', '=', 'image_tag.image_id')
->join('tags', 'tags.id', '=', 'image_tag.tag_id')
->whereIn('tags.id', $tags)
->groupBy('images.download_url')
->having('TheCount', count($tags))
->get();
If you need more than just the download_url
for each image, you might need to change it up a bit. I'd suggest instead of selecting and grouping by download_url
, do it by the image's id
and then you can set it up as a subselect and join it back up with the images table on the matching id's if that makes any sense.
Or just use ->lists('images.id')
to get the array of id's and make another query on the images table getting all images in that list of id's.
Manual count and having
would work, but you can use simple whereHas
instead:
// let it be array of tag ids:
$tagsIds;
$images = Image::whereHas('tags', function ($q) use ($tagsIds) {
$q->whereIn('tags.id', $tagsIds);
}, '=', count($tagsIds))->get();
However mind that both mine and @user3158900's solutions will work only, when you have no duplicates on the pivot table. Using Eloquent's attach
method on BelongsToMany
relation may lead to such situation.