12

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.

Marion Newlevant
  • 12,047
  • 22
  • 55

2 Answers2

11

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

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

More on searching here.

Ben Croker
  • 7,341
  • 26
  • 55
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 %}
Stuart Whitehead
  • 1,214
  • 8
  • 19