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.

2 Answers 2


You can do this in a single query using the search parameter:

{% set uncategorized = craft.entries.section('news').search('-categories:*') %}

More on searching here.

  • Cool, nice answer. Jul 1, 2014 at 14:36
  • This is returning all of my entries, including the one with a category in news.categories Jul 1, 2014 at 19:06
  • strange, it works for me. are you on v2.1 and is your field handle "categories"?
    – Ben Croker
    Jul 1, 2014 at 20:49
  • very latest 2.1.2561 and field handle categories. The category group is newsCategory Jul 2, 2014 at 3:16
  • can you rebuild the search indexes (on the settings page) and then try again?
    – Ben Croker
    Jul 2, 2014 at 11:36

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 %}
  • That loop is looking better and better. Jun 30, 2014 at 17:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.