---
title: "Querying models — Tags for Laravel | Roundly"
description: "withAnyTags, withAllTags, withoutTags and withTagsOf — with descendants and scopes — plus the inverse taggedModels() relation."
url: https://roundly-consulting.com/open-source/docs/tags-for-laravel/querying
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Tags for Laravel](https://roundly-consulting.com/open-source/docs/tags-for-laravel.md)

# Querying models

Four query scopes on every taggable model, combined freely with the rest of your query — and the same implementation behind TagsFilter, so PHP and HTTP filter identically:

```php
// Music, Jazz, Bebop, … — descendants: matches every tag below a hierarchical one
$page = Concert::withAnyTags(['music'], 'genre', descendants: true)
    ->withAllTags(['outdoor', 'free'], 'label')
    ->withoutTags(['sold-out'], 'label')
    ->paginate();

Concert::withoutTags(type: 'genre')->count();      // concerts with no category yet
Concert::withoutTags()->count();                   // concerts with no tag at all
Concert::withTagsOf('label')->count();             // concerts with at least one label

Concert::withAnyTags([$jazz, $rock])->get();       // models carry their own type
Concert::withAllTags(['live', 'unknown'], 'label')->get();   // an unknown string matches nothing
```

| Scope | Meaning |
| --- | --- |
| `withAnyTags($tags, $type = null, descendants: false, within: null)` | Models carrying at least one of the tags. |
| `withAllTags($tags, $type = null, descendants: false, within: null)` | Models carrying every one of them — each satisfied by itself or, with descendants, by a tag below it. A string that names no tag matches no model. |
| `withoutTags($tags = [], $type = null, descendants: false, within: null)` | Models carrying none of them; with no tags, models with no tag of the type — or no tag at all without a type. |
| `withTagsOf($type)` | Models carrying at least one tag of the type. |

- Inputs are tag models, keys or strings, like the tagging verbs. Strings resolve without creating; an unknown string matches nothing — in withAllTags that means no model.
- A type narrows strings to that type and the match to taggings of it. Without a type, strings use the default type and models and keys carry their own.
- Each scope is a whereIn over a taggings subquery: no join, no duplicate rows, safe to paginate.
- The tagging pivot and the model must share one database connection — tags:doctor warns when a model lives elsewhere.

## From a tag to its models

$tag->taggedModels(Concert::class) is the inverse relation, read-only like tags(); $tag->taggings() returns the raw pivot rows.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/tags-for-laravel.md)
