<p>If you're wanting to avoid a loop, I think the best solution here would be to find the entries which <em>do</em> have a category set and work backwards using the <a href="http://buildwithcraft.com/docs/templating/filters#without" rel="nofollow"><code>|without()</code></a> filter. I can't see this being possible in only one query.</p>

<pre><code>{# First, get your categories #}
{% set categories = craft.categories.group('optionalGroup').ids() %}

{# Find all news entries which have a category set #}
{% set newsWithCategories = craft.entries.section('news').relatedTo({targetElement: categories}).ids() %}

{# Now find news without categories #}
{% set newsWithoutCategories = craft.entries.section('news').ids()|without(newsWithCategories) %}

{# Finally retrieve the EntryModels #}
{% set newsEntries = craft.entries.section('news').id(newsWithoutCategories).find() %}
</code></pre>

<p>As you can see, there are quite a few calls to the DB being made here. This little algorithm would probably be more efficient with a loop.</p>

<pre><code>{% set newsEntries = [] %}
{% for news in craft.entries.section('news').find() %}
    {% if news.categories is empty %}
        {% set newsEntries = newsEntries|merge([news]) %}
    {% endif %}
{% endfor %}
</code></pre>

CC BY-SA 3.0
2014-06-30T17:25:12.377Z
That loop is looking better and better.
Marion Newlevant
CC BY-SA 3.0
2014-06-30T11:14:23.630Z
2014-06-30T11:14:23.630Z
Stuart Whitehead
<p>You can do this in a single query using the search parameter:</p>

<pre class="lang-twig prettyprint-override"><code>{% set uncategorized = craft.entries.section('news').search('-categories:*') %}
</code></pre>

<p>More on <a href="http://buildwithcraft.com/docs/searching">searching here</a>.</p>

CC BY-SA 3.0
2014-07-01T14:36:30.833Z
Cool, nice answer.
Stuart Whitehead
CC BY-SA 3.0
2014-07-01T19:06:41.877Z
This is returning all of my entries, including the one with a category in news.categories
Marion Newlevant
CC BY-SA 3.0
2014-07-01T20:49:27.500Z
strange, it works for me. are you on v2.1 and is your field handle "categories"?
Ben Croker
CC BY-SA 3.0
2014-07-02T03:16:28.713Z
very latest 2.1.2561 and field handle categories. The category group is newsCategory
Marion Newlevant
CC BY-SA 3.0
2014-07-02T11:36:46.923Z
can you rebuild the search indexes (on the settings page) and then try again?
Ben Croker
CC BY-SA 3.0
2014-07-03T05:30:39.743Z
That fixed it! And also the parallel problem I was having with untagged entries. Thank you so much!
Marion Newlevant
CC BY-SA 3.0
2014-07-03T09:06:11.287Z
great, i've reported a bug to P&T which should address this issue in future
Ben Croker
CC BY-SA 3.0
2014-07-08T16:19:49.953Z
fixed in this update http://buildwithcraft.com/updates#build2563
Ben Croker
CC BY-SA 3.0
2014-07-01T11:37:23.280Z
2014-07-01T11:37:23.280Z
Ben Croker
<p>I have a field <code>categories</code> in a channel <code>news</code>, and I want to find all the entries in <code>news</code> that don't have a category set. I know I could loop over the entries and find them that way, but I'm hoping to do it with a query. I tried</p>

<pre><code>{% set uncategorized = craft.entries.section('news').categories(':empty:') %}
</code></pre>

<p>But it returned none.</p>

<categories><elementcriteriamodel>
How to find entries with no category
# How to find entries with no category

(Asked by: username_0 on 2014-06-30)

I have a field categories in a channel news, and I want to find all the entries in news that don't have a category set. I know I could loop over the entries and find them that way, but I'm hoping to do it with a query. I tried
{% set uncategorized = craft.entries.section('news').categories(':empty:') %}

But it returned none.

**Tags:** categories, elementcriteriamodel


---

## 2 answers

### Answer by username_2 on 2014-07-01. Score: 11 | Accepted answer

You can do this in a single query using the search parameter:
{% set uncategorized = craft.entries.section('news').search('-categories:*') %}

More on searching here.

> **Comments:**
> **username_1**: Cool, nice answer.  
> **username_0**: This is returning all of my entries, including the one with a category in news.categories  
> **username_2**: strange, it works for me. are you on v2.1 and is your field handle "categories"?  
> **username_0**: very latest 2.1.2561 and field handle categories. The category group is newsCategory  
> **username_2**: can you rebuild the search indexes (on the settings page) and then try again?  
> **username_0**: That fixed it! And also the parallel problem I was having with untagged entries. Thank you so much!  
> **username_2**: great, i've reported a bug to P&T which should address this issue in future  
> **username_2**: fixed in this update http://buildwithcraft.com/updates#build2563  

---

### Answer by username_1 on 2014-06-30. Score: 4

If you're wanting to avoid a loop, I think the best solution here would be to find the entries which do have a category set and work backwards using the |without() filter. I can't see this being possible in only one query.
{# First, get your categories #}
{% set categories = craft.categories.group('optionalGroup').ids() %}

{# Find all news entries which have a category set #}
{% set newsWithCategories = craft.entries.section('news').relatedTo({targetElement: categories}).ids() %}

{# Now find news without categories #}
{% set newsWithoutCategories = craft.entries.section('news').ids()|without(newsWithCategories) %}

{# Finally retrieve the EntryModels #}
{% set newsEntries = craft.entries.section('news').id(newsWithoutCategories).find() %}

As you can see, there are quite a few calls to the DB being made here. This little algorithm would probably be more efficient with a loop.
{% set newsEntries = [] %}
{% for news in craft.entries.section('news').find() %}
    {% if news.categories is empty %}
        {% set newsEntries = newsEntries|merge([news]) %}
    {% endif %}
{% endfor %}

> **Comments:**
> **username_0**: That loop is looking better and better.  

---

