Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-09-23T19:16:45.603Z
Answers.Text: Thanks a lot! Adding sort fixed it. 
  
  And thanks for the matrix block query example. Might be handy for future projects.
Answers.UserDisplayName: Rinus
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-09-23T15:25:05.197Z
Answers.LastActivityDate: 2020-09-23T15:25:05.197Z
Answers.UserDisplayName: James Smith
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-09-24T19:14:00.467Z
Answers.LastActivityDate: 2020-09-24T19:14:00.467Z
Answers.UserDisplayName: Rinus
Body: <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>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-09-23T09:00:16.890Z
Comments.Text: What type of field is `trainingDates`?
Comments.UserDisplayName: James Smith
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-09-23T13:04:29.153Z
Comments.Text: @JamesSmith trainingdates is a maxtrix field.
Comments.UserDisplayName: Rinus
Tags: <craft3><query>
Title: Order entries by multiple matrix date field
ThreadText: # 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 #}
  <ul>
      {% for startDate in startDates %}
          <li>
              <h2>{{ startDate }}</h2>
              <ul>
                  {% for entry in allEntries %}
                      {% for date in entry.trainingDates.all() %}
                          {% if date.startDate | date('d mm Y') == startDate %}
                              <li><a href="{{ entry.url }}" title="{{ entry.title }}">{{ entry.title }}</a></li>
                          {% endif %}
                      {% endfor %}
                  {% endfor %}
              </ul>
          </li>
      {% endfor %}
  </ul>
  
  ```
  
  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**: @username_1 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#}
  <ul>
      {% for startDate in startDates|sort %}
          <li>
              <h2>{{ startDate }}</h2>
              <ul>
                  {% for entry in allEntries %}
                      {% for date in entry.trainingDates %}
                          {% if date.startDate | date('d mm Y') == startDate %}
                              <li><a href="{{ entry.url }}" title="{{ entry.title }}">{{ entry.title }}</a></li>
                          {% endif %}
                      {% endfor %}
                  {% endfor %}
              </ul>
          </li>
      {% endfor %}
  </ul>
  
  ```
  
  (I've also added [eager loading](https://craftcms.com/docs/3.x/dev/eager-loading-elements.html) 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#}
  <ul>
      {% for startDate in uniqueDatesSorted %}
          <li>
              <h2>{{ startDate }}</h2>
              <ul>
                  {% for entry in allEntries %}
                      {% for date in entry.trainingDates %}
                          {% if date.startDate|date('d mm Y') == startDate %}
                              <li><a href="{{ entry.url }}" title="{{ entry.title }}">{{ date.id }}{{ entry.title }}</a></li>
                          {% endif %}
                      {% endfor %}
                  {% endfor %}
              </ul>
          </li>
      {% endfor %}
  </ul>
  
  ```
  
  ...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.
  
  
  ---
  
  