<p>The quick and easy answer would be to just add the Twig <code>sort</code> filter to your startDates array. e.g:</p>
<pre><code>{# Query entries that have training dates #}
{% set allEntries = craft.entries
    .section('trainings')
    .with('trainingDates')
    .trainingDates(':notempty:')
    .all()
%}

{# Merge all training dates in an array #}
{% set startDates = [] %}
{% for entry in allEntries %}
    {% for training in entry.trainingDates %}
        {% if training.startDate | date('d mm Y') not in startDates %}
            {% set startDates = startDates | push(training.startDate | date('d mm Y')) %}
        {% endif %}
    {% endfor %}
{% endfor %}

{# Show all trainings grouped by date#}
&lt;ul&gt;
    {% for startDate in startDates|sort %}
        &lt;li&gt;
            &lt;h2&gt;{{ startDate }}&lt;/h2&gt;
            &lt;ul&gt;
                {% for entry in allEntries %}
                    {% for date in entry.trainingDates %}
                        {% if date.startDate | date('d mm Y') == startDate %}
                            &lt;li&gt;&lt;a href=&quot;{{ entry.url }}&quot; title=&quot;{{ entry.title }}&quot;&gt;{{ entry.title }}&lt;/a&gt;&lt;/li&gt;
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            &lt;/ul&gt;
        &lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</code></pre>
<p>(I've also added <a href="https://craftcms.com/docs/3.x/dev/eager-loading-elements.html" rel="nofollow noreferrer">eager loading</a> to improve performance).</p>
<p>You could potentially attack the problem from the opposite direction by using a matrixblock element query like this:</p>
<pre><code>{# Query matrix blocks that have training dates #}
{% set matrixBlocksQuery = craft.matrixBlocks().field('trainingDates') %}
{% set uniqueDatesSorted = matrixBlocksQuery.all()|map(block =&gt; block.startDate|date('d mm Y'))|unique|sort %}

{# Query entries that have training dates #}
{% set allEntries = craft.entries
    .section('trainings')
    .with('trainingDates')
    .trainingDates(':notempty:')
    .all()
%}

{# Show all trainings grouped by date#}
&lt;ul&gt;
    {% for startDate in uniqueDatesSorted %}
        &lt;li&gt;
            &lt;h2&gt;{{ startDate }}&lt;/h2&gt;
            &lt;ul&gt;
                {% for entry in allEntries %}
                    {% for date in entry.trainingDates %}
                        {% if date.startDate|date('d mm Y') == startDate %}
                            &lt;li&gt;&lt;a href=&quot;{{ entry.url }}&quot; title=&quot;{{ entry.title }}&quot;&gt;{{ date.id }}{{ entry.title }}&lt;/a&gt;&lt;/li&gt;
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            &lt;/ul&gt;
        &lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</code></pre>
<p>...but to be honest I think I prefer your approach, as it's more readable and doesn't require an extra <code>.all()</code> query to get the dates</p>

CC BY-SA 4.0
2020-09-23T19:16:45.603Z
Thanks a lot! Adding sort fixed it. 

And thanks for the matrix block query example. Might be handy for future projects.
Rinus
CC BY-SA 4.0
2020-09-23T15:25:05.197Z
2020-09-23T15:25:05.197Z
James Smith
<p>I loaded a database with 50+ trainings and the sort was wrong again. And I figured out why.</p>
<p>I pushed all the dates in an array with the date format like date('d mm Y'). Dates would be 03 november 2020, 17 october 2020, 01 december 2020, etc. The templates used the first two numbers to sort. So the entries started with december, then november and then october.</p>
<p>I changed the date format to date('c') and now all the entries are sorted fine. Later on in the loop I displayed the startdate with {{ startDate | date(&quot;d mm Y&quot;) }}.</p>
<p>So anyone trying to do the same, date('c') does the trick.</p>

CC BY-SA 4.0
2020-09-24T19:14:00.467Z
2020-09-24T19:14:00.467Z
Rinus
<p>I have a section with trainings. In each training entry there's a matrix field where we add a new block with a training date, location, etc. So each training has multiple matrix blocks.</p>
<p>When I run an entry query and get all the matrix date fields inside of them, I can output it like this:</p>
<ul>
<li>Training 1
<ul>
<li>October 1, 2020</li>
<li>October 5, 2020</li>
</ul>
</li>
<li>Training 2
<ul>
<li>October 5, 2020</li>
<li>October 10, 2020</li>
</ul>
</li>
<li>Training 3
<ul>
<li>October 7, 2020</li>
<li>October 10, 2020</li>
</ul>
</li>
</ul>
<p>Now I would like to group and order the trainings by date like this:</p>
<ul>
<li>October 1, 2020
<ul>
<li>Training 1</li>
</ul>
</li>
<li>October 5, 2020
<ul>
<li>Training 1</li>
<li>Training 2</li>
</ul>
</li>
<li>October 7, 2020
<ul>
<li>Training 3</li>
</ul>
</li>
<li>October 10, 2020
<ul>
<li>Training 2</li>
<li>Training 3</li>
</ul>
</li>
</ul>
<p>I'm close but can't get the dates sorted the right way. The template currently outputs:</p>
<ul>
<li>October 1, 2020
<ul>
<li>Training 1</li>
</ul>
</li>
<li>October 5, 2020
<ul>
<li>Training 1</li>
<li>Training 2</li>
</ul>
</li>
<li>October 10, 2020
<ul>
<li>Training 2</li>
<li>Training 3</li>
</ul>
</li>
<li>October 7, 2020
<ul>
<li>Training 3</li>
</ul>
</li>
</ul>
<p>The code I have right now:</p>
<pre><code>{# Query entries that have training dates #}
{% set allEntries = craft.entries
.section('trainings')
.trainingDates(':notempty:')
.all() %}

{# Merge all training dates in an array #}
{% set startDates = [] %}
{% for entry in allEntries %}
    {% for training in entry.trainingDates.all() %}
        {% if training.startDate | date('d mm Y') not in startDates %}
            {% set startDates = startDates | push(training.startDate | date('d mm Y')) %}
        {% endif %}
    {% endfor %}
{% endfor %}

{# Show all trainings grouped by date #}
&lt;ul&gt;
    {% for startDate in startDates %}
        &lt;li&gt;
            &lt;h2&gt;{{ startDate }}&lt;/h2&gt;
            &lt;ul&gt;
                {% for entry in allEntries %}
                    {% for date in entry.trainingDates.all() %}
                        {% if date.startDate | date('d mm Y') == startDate %}
                            &lt;li&gt;&lt;a href=&quot;{{ entry.url }}&quot; title=&quot;{{ entry.title }}&quot;&gt;{{ entry.title }}&lt;/a&gt;&lt;/li&gt;
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            &lt;/ul&gt;
        &lt;/li&gt;
    {% endfor %}
&lt;/ul&gt;
</code></pre>
<p>Any idea on how to sort the array by date? And this can probably done much easier. If you have any tips, I would love to hear from you! :-)</p>

CC BY-SA 4.0
2020-09-23T09:00:16.890Z
What type of field is `trainingDates`?
James Smith
CC BY-SA 4.0
2020-09-23T13:04:29.153Z
@JamesSmith trainingdates is a maxtrix field.
Rinus
<craft3><query>
Order entries by multiple matrix date field
# Order entries by multiple matrix date field

(Asked by: username_0 on 2020-09-22)

I have a section with trainings. In each training entry there's a matrix field where we add a new block with a training date, location, etc. So each training has multiple matrix blocks.
When I run an entry query and get all the matrix date fields inside of them, I can output it like this:

Training 1

October 1, 2020
October 5, 2020


Training 2

October 5, 2020
October 10, 2020


Training 3

October 7, 2020
October 10, 2020



Now I would like to group and order the trainings by date like this:

October 1, 2020

Training 1


October 5, 2020

Training 1
Training 2


October 7, 2020

Training 3


October 10, 2020

Training 2
Training 3



I'm close but can't get the dates sorted the right way. The template currently outputs:

October 1, 2020

Training 1


October 5, 2020

Training 1
Training 2


October 10, 2020

Training 2
Training 3


October 7, 2020

Training 3



The code I have right now:
{# Query entries that have training dates #}
{% set allEntries = craft.entries
.section('trainings')
.trainingDates(':notempty:')
.all() %}

{# Merge all training dates in an array #}
{% set startDates = [] %}
{% for entry in allEntries %}
    {% for training in entry.trainingDates.all() %}
        {% if training.startDate | date('d mm Y') not in startDates %}
            {% set startDates = startDates | push(training.startDate | date('d mm Y')) %}
        {% endif %}
    {% endfor %}
{% endfor %}

{# Show all trainings grouped by date #}

    {% for startDate in startDates %}
        
            {{ startDate }}
            
                {% for entry in allEntries %}
                    {% for date in entry.trainingDates.all() %}
                        {% if date.startDate | date('d mm Y') == startDate %}
                            {{ entry.title }}
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            
        
    {% endfor %}


Any idea on how to sort the array by date? And this can probably done much easier. If you have any tips, I would love to hear from you! :-)

**Tags:** craft3, query
> **Comments:**
> **username_1**: What type of field is `trainingDates`?  
> **username_0**: @JamesSmith trainingdates is a maxtrix field.  

---

## 2 answers

### Answer by username_1 on 2020-09-23. Score: 2 | Accepted answer

The quick and easy answer would be to just add the Twig sort filter to your startDates array. e.g:
{# Query entries that have training dates #}
{% set allEntries = craft.entries
    .section('trainings')
    .with('trainingDates')
    .trainingDates(':notempty:')
    .all()
%}

{# Merge all training dates in an array #}
{% set startDates = [] %}
{% for entry in allEntries %}
    {% for training in entry.trainingDates %}
        {% if training.startDate | date('d mm Y') not in startDates %}
            {% set startDates = startDates | push(training.startDate | date('d mm Y')) %}
        {% endif %}
    {% endfor %}
{% endfor %}

{# Show all trainings grouped by date#}

    {% for startDate in startDates|sort %}
        
            {{ startDate }}
            
                {% for entry in allEntries %}
                    {% for date in entry.trainingDates %}
                        {% if date.startDate | date('d mm Y') == startDate %}
                            {{ entry.title }}
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            
        
    {% endfor %}


(I've also added eager loading to improve performance).
You could potentially attack the problem from the opposite direction by using a matrixblock element query like this:
{# Query matrix blocks that have training dates #}
{% set matrixBlocksQuery = craft.matrixBlocks().field('trainingDates') %}
{% set uniqueDatesSorted = matrixBlocksQuery.all()|map(block => block.startDate|date('d mm Y'))|unique|sort %}

{# Query entries that have training dates #}
{% set allEntries = craft.entries
    .section('trainings')
    .with('trainingDates')
    .trainingDates(':notempty:')
    .all()
%}

{# Show all trainings grouped by date#}

    {% for startDate in uniqueDatesSorted %}
        
            {{ startDate }}
            
                {% for entry in allEntries %}
                    {% for date in entry.trainingDates %}
                        {% if date.startDate|date('d mm Y') == startDate %}
                            {{ date.id }}{{ entry.title }}
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            
        
    {% endfor %}


...but to be honest I think I prefer your approach, as it's more readable and doesn't require an extra .all() query to get the dates

> **Comments:**
> **username_0**: Thanks a lot! Adding sort fixed it.   And thanks for the matrix block query example. Might be handy for future projects.  

---

### Answer by username_0 on 2020-09-24. Score: 1

I loaded a database with 50+ trainings and the sort was wrong again. And I figured out why.

I pushed all the dates in an array with the date format like date('d mm Y'). Dates would be 03 november 2020, 17 october 2020, 01 december 2020, etc. The templates used the first two numbers to sort. So the entries started with december, then november and then october.

I changed the date format to date('c') and now all the entries are sorted fine. Later on in the loop I displayed the startdate with {{ startDate | date("d mm Y") }}.

So anyone trying to do the same, date('c') does the trick.


---

