<p>Assuming you can't change your data model easily to use relationships pointing to a 2-level Structure for State &gt; Suburb (which would be a more robust approach), you can use the <code>group</code> filter to create 2-dimensional arrays like this:</p>
<pre class="lang-twig prettyprint-override"><code>{% set buildings = craft.entries.section('buildings').authorId(currentUser.id).all() %}
{% set buildingsByState = buildings|group(building =&gt; building.state) %}
&lt;ul&gt;
    {% for state, buildingsInState in buildingsByState %}
        &lt;li&gt;
            &lt;h3&gt;{{ state }}&lt;/h3&gt;
            {% for suburb, buildingsInSuburb in buildingsInState|group(building =&gt; building.suburb) %}
                &lt;h4&gt;{{ suburb }}&lt;/h4&gt;
                &lt;ul&gt;
                    {% for building in buildingsInSuburb %}
                        &lt;li&gt;{{ building.title }}&lt;/li&gt;
                    {% endfor %}
                &lt;/ul&gt;
            {% endfor %}
        &lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</code></pre>

CC BY-SA 4.0
2023-08-21T11:26:27.337Z
2023-08-21T11:26:27.337Z
James Smith
<p>Wasn't that hard actually, just needed to stop and think about it for a bit.</p>
<pre><code>{% set buildings = craft.entries.authorId(currentUser.id) %}
{% set states = [] %}
{% set suburbs = [] %}
{% for building in buildings %}
    {% set states = states|merge([building.state])|unique %}
    {% set suburbs = suburbs|merge([building.suburb])|unique %}
{% endfor %}

&lt;ul&gt;
    {% for state in states %}
    &lt;li&gt;
        &lt;div&gt;{{ state }}&lt;/div&gt;
        &lt;ul&gt;
            {% for suburb in suburbs %}
            &lt;li&gt;
               {{ suburb }}
                &lt;ul&gt;
                    {% set addresses = craft.entries.authorId(currentUser.id).suburb(suburb) %}
                    {% for address in addresses %}
                    &lt;li&gt;{{ address.title }}&lt;/li&gt;
                    {% endfor %}
                &lt;/ul&gt;
            &lt;/li&gt;
            {% endfor %}
        &lt;/ul&gt;
    &lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</code></pre>

CC BY-SA 4.0
2023-08-18T08:43:32.913Z
Be careful with this solution - you've created an N+1 problem here by having a query inside a loop - and a nested loop at that, which will compound the problem. Every entry that gets added will progressively degrade the performance of this. Turn on your template debugger and keep an eye on the DB query count and timing. Are your states and suburbs relationship fields (entries/categories) or plain text/dropdowns?
James Smith
CC BY-SA 4.0
2023-08-21T00:09:42.160Z
@JamesSmith Plain text fields
Tyssen
CC BY-SA 4.0
2023-08-21T10:53:25.323Z
You also seem to be looping through _all_ suburbs here, not just the ones that belong to the current state. If it's not too late I'd recommend you refine your content model so that states and suburbs are a 2-level Structure (a suburb can never be a child of more than one state, so this is a suitable setup). It'll also improve your data quality by avoiding typos or alternate spellings. Even someone putting a space or capital letter in the wrong place could spoil your output.
James Smith
CC BY-SA 4.0
2023-08-18T01:27:19.667Z
2023-08-18T01:27:19.667Z
Tyssen
<p>I have a section for addresses which has fields for <code>address</code>, <code>state</code>, <code>suburb</code> and <code>postcode</code>. On the front end, I want to display them like this:</p>
<pre><code>State 1
- Suburb 1
-- Address 1
-- Address 2
- Suburb 2
-- Address 1
-- Address 2
</code></pre>
<p>so in other words, they'd be grouped by their state and then by their suburb. How would I go about doing that?</p>

<group>
Group entries by custom fields
# Group entries by custom fields

(Asked by: username_0 on 2023-08-18)

I have a section for addresses which has fields for address, state, suburb and postcode. On the front end, I want to display them like this:
State 1
- Suburb 1
-- Address 1
-- Address 2
- Suburb 2
-- Address 1
-- Address 2

so in other words, they'd be grouped by their state and then by their suburb. How would I go about doing that?

**Tags:** group


---

## 2 answers

### Answer by username_1 on 2023-08-21. Score: 2 | Accepted answer

Assuming you can't change your data model easily to use relationships pointing to a 2-level Structure for State > Suburb (which would be a more robust approach), you can use the group filter to create 2-dimensional arrays like this:
{% set buildings = craft.entries.section('buildings').authorId(currentUser.id).all() %}
{% set buildingsByState = buildings|group(building => building.state) %}

    {% for state, buildingsInState in buildingsByState %}
        
            {{ state }}
            {% for suburb, buildingsInSuburb in buildingsInState|group(building => building.suburb) %}
                {{ suburb }}
                
                    {% for building in buildingsInSuburb %}
                        {{ building.title }}
                    {% endfor %}
                
            {% endfor %}
        
    {% endfor %}


---

### Answer by username_0 on 2023-08-18. Score: 1

Wasn't that hard actually, just needed to stop and think about it for a bit.
{% set buildings = craft.entries.authorId(currentUser.id) %}
{% set states = [] %}
{% set suburbs = [] %}
{% for building in buildings %}
    {% set states = states|merge([building.state])|unique %}
    {% set suburbs = suburbs|merge([building.suburb])|unique %}
{% endfor %}


    {% for state in states %}
    
        {{ state }}
        
            {% for suburb in suburbs %}
            
               {{ suburb }}
                
                    {% set addresses = craft.entries.authorId(currentUser.id).suburb(suburb) %}
                    {% for address in addresses %}
                    {{ address.title }}
                    {% endfor %}
                
            
            {% endfor %}
        
    
    {% endfor %}

> **Comments:**
> **username_1**: Be careful with this solution - you've created an N+1 problem here by having a query inside a loop - and a nested loop at that, which will compound the problem. Every entry that gets added will progressively degrade the performance of this. Turn on your template debugger and keep an eye on the DB query count and timing. Are your states and suburbs relationship fields (entries/categories) or plain text/dropdowns?  
> **username_0**: @JamesSmith Plain text fields  
> **username_1**: You also seem to be looping through _all_ suburbs here, not just the ones that belong to the current state. If it's not too late I'd recommend you refine your content model so that states and suburbs are a 2-level Structure (a suburb can never be a child of more than one state, so this is a suitable setup). It'll also improve your data quality by avoiding typos or alternate spellings. Even someone putting a space or capital letter in the wrong place could spoil your output.  

---

