<p>Yeah you are probably better off putting the startDate, endDate, and price in non matrix fields.  But if you don't something like this should probably work:</p>

<pre><code>{# Get your list of entries (you probably don't want to start with all  entries, this is just an example #}
{% for entry in entries %}
    {# get the matrix field you want to sort things with #}
    {% for block in entry.yourTravelMatrix %}
        {# get the matrix block by type #}
        {% if block.type == "startDateBlock" %}
            {# set a variable to be the date in the field  #}
            {% set startDateVariable = block.startDateField %}
            {# use the variable to filter the entries #}
            {% if startDateVariable &gt;= (now | date_modify("+1 months") %}
                {# whatever data you want to show from the entries #}
                {{ entry.title }}
            {% endif %}
        {% endif %}
    {% endfor %}
{% endfor %}
</code></pre>

<p>You'll probably have to adjust it a bit since dateTime fields are different than plain text fields.  There may be a better way to filter by a Matrix field.  Filtering by fields that aren't in a matrix is a lot easier.  This should basically work though.</p>

CC BY-SA 3.0
2015-04-09T04:47:38.993Z
Thanks @jason. We share the thought. However there's a small issue with this approach. I cannot paginate the result set, which is quite long.
thoaionline
CC BY-SA 3.0
2015-04-08T13:26:24.033Z
2015-04-08T13:45:56.667Z
2015-04-08T13:45:56.667Z
Jason
<p>I would like to propose something similar to this as a potential solution:</p>

<pre><code>{# Matrix Search - Reasonably Elegant Solution #}

{# Initialise Matrix Block Owner IDs array #}
{% set matrixBlockOwnerIds = [] %}

{# This seems to be the easiest way to get the criteria in the shortest route #}
{% set ecm = craft.entries.section('mySectionHandle').type('myEntryTypeHandle').first().someMatrixBlockTypeHandle %}

{# Reset the owner ID because it was set by the first search #}
{% do ecm.setAttribute('ownerId', NULL) %}

{# Up the limit for a test - can be removed #}
{% do ecm.setAttribute('limit', 1000) %}

{# Set some search criteria #}
{% do ecm.setAttribute('startDate', '&gt;= 2015-06-01') %}
{% do ecm.setAttribute('endDate', '&lt;= 2015-07-01') %}

{# Find matching blocks #}
{% set matrixBlocks = ecm.find() %}

{# Iterate blocks and extract owner IDs (entry IDs) #}
{% for block in matrixBlocks %}
    {% set matrixBlockOwnerIds = matrixBlockOwnerIds|merge([block.ownerId]) %}
{% endfor %}

{# Query the entries by ID #}
{% set entries = craft.entries.find({'id': matrixBlockOwnerIds}) %}

{# Iterate entries #}
{% for entry in entries %}
    &lt;h2&gt;{{ entry.title }}&lt;/h2&gt;
    {# Unfortunately we need to get the matrix blocks again, but this will include all blocks for the entry of that type #}
    {% for block in entry.someMatrixBlockTypeHandle.find() %}
        {# Output some block values #}
        &lt;p&gt;{{ block.valueA }} - {{ block.valueB }}&lt;/p&gt;
    {% endfor %}
{% endfor %}
</code></pre>

<p>This isn't exact to your needs but I'm pretty sure it can be adjusted.</p>

<p>You can also do this for numeric ranges: </p>

<pre><code>{% do ecm.setAttribute('someNumericValue', ['and', '&gt; 10', '&lt; 20') %}
</code></pre>

<p>If you need to combine AND and OR for the same field you'd have to repeat the search with the 'and' set to or, but not reset the matrixBlockOwnerIds array ..</p>

<p>e.g.</p>

<pre><code>{% do ecm.setAttribute('someNumericValue', ['and', '&gt; 10', '&lt; 20') %}

{% set matrixBlocks = ecm.find() %}

{% for block in matrixBlocks %}
    {% set matrixBlockOwnerIds = matrixBlockOwnerIds|merge([block.ownerId]) %}
{% endfor %}

{% do ecm.setAttribute('someNumericValue', ['and', '&gt; 10', '&lt; 20') %}

{% set matrixBlocks = ecm.find() %}

{% for block in matrixBlocks %}
    {% set matrixBlockOwnerIds = matrixBlockOwnerIds|merge([block.ownerId]) %}
{% endfor %}
</code></pre>

<p>If you need any help with these examples, just give me a message.</p>

CC BY-SA 3.0
2015-06-09T17:09:42.933Z
2015-06-09T17:09:42.933Z
Jay
<p>What I've done in a comparable situation is to add a hidden field to that entry type. And then I save Matrix data to that field on every save by listening to <a href="http://buildwithcraft.com/docs/plugins/events-reference#entries-onBeforeSaveEntry" rel="nofollow"><code>onBeforeSaveEntry</code></a> events.</p>

<p>This makes the access to such processed Matrix data in templates or other parts of your plugin (i.e. <a href="http://buildwithcraft.com/docs/plugins/hooks-reference#getEntryTableAttributeHtml" rel="nofollow"><code>getEntryTableAttributeHtml</code></a>) very easy.</p>

<p><strong>Event handler</strong></p>

<pre><code>craft()-&gt;on('entries.onBeforeSaveEntry', function(Event $event)
{
    $entry = $event-&gt;params['entry'];

    if($entry-&gt;section['handle'] == 'campaigns')
    {
        $longTravels = false;

        foreach ($entry-&gt;travelDates as $travelDate)
        {
            $duration = $travelDate-&gt;startDate-&gt;diff($travelDate-&gt;endDate);

            if ($duration &gt; new DateInterval('P30D') &amp;&amp; $duration &lt; new DateInterval('P60D'))
            {
                $longTravels = true;
                break;
            }
        }

        // Set value for hidden field 'longTravels'
        $entry-&gt;getContent()-&gt;longTravels = $longTravels;
    }
});
</code></pre>

<p><strong>CSS for hidden field type</strong></p>

<pre><code>{% set hiddenField %}
    #fields-{{ id }}-field {
        display: none;
    }
{% endset %}

{% includeCss hiddenField %}
</code></pre>

CC BY-SA 3.0
2017-08-22T12:46:20.870Z
Along this route, you also might want to check out the [Preparse Field](https://github.com/aelvan/Preparse-Field-Craft) plugin – it sure helped me fetch the relevant data that was stored within a matrix.
Avant la lettre
CC BY-SA 3.0
2017-08-23T06:27:06.523Z
@Avantlalettre good suggestion, I think I wrote this answer before the Preparse plugin existed. Today, I use Preparse a lot for these kind of things. You might want to post your comment as a separate answer though, it’s a bit burried in all this text and code. I’d definitly upvote it (and accept, if it was my decision :D).
carlcs
CC BY-SA 3.0
2015-04-08T15:17:22.500Z
2015-04-08T15:28:39.410Z
2015-04-08T15:28:39.410Z
carlcs
<p>I'm building a travel site containing Campaigns (entries)</p>

<p>Each of these campaigns has multiple travel dates, modelled by a matrix field of</p>

<p>[startDate, endDate, price]</p>

<p>I want to do the following searches:</p>

<ul>
<li>Campaigns with a travel startDate next month</li>
<li>Campaigns whose duration is more than 30 days and less than 60 days (endDate-startDate)</li>
<li>One of those criteria</li>
<li>All of the above criteria</li>
</ul>

<p>How can this be achieved with twig template or custom controller?</p>

<p>PS: I looked into <a href="http://buildwithcraft.com/docs/relations" rel="noreferrer">relations</a> but that only applies to <code>entries</code> field, not matrix, and neither does it allow filtering on the related entity.</p>

CC BY-SA 3.0
2015-04-08T12:48:45.143Z
I'd seriously question the use of a matrix field for that sort of data - sounds like all of those values will be required for each entry and moving them to their own fields would make those searches a lot simpler.
Adam Gilleard
CC BY-SA 3.0
2015-04-08T13:39:29.487Z
@Adam you're right, it is a lot simpler to filter entries by direct fields, but this shouldn't be a reason to decide against Matrix. You probably missed that the OP mentioned that each of these entries "campaigns" got multiple (maybe even optional) Matrix blocks "Travel dates".
carlcs
CC BY-SA 3.0
2015-04-08T14:22:00.107Z
@carlcs you're right, I had missed the potential for multiple dates - apologies
Adam Gilleard
<matrix><field><search>
Search for entries with matrix field's value
# Search for entries with matrix field's value

(Asked by: username_0 on 2015-04-08)

I'm building a travel site containing Campaigns (entries)

Each of these campaigns has multiple travel dates, modelled by a matrix field of

[startDate, endDate, price]

I want to do the following searches:

* Campaigns with a travel startDate next month
* Campaigns whose duration is more than 30 days and less than 60 days (endDate-startDate)
* One of those criteria
* All of the above criteria

How can this be achieved with twig template or custom controller?

PS: I looked into [relations](http://buildwithcraft.com/docs/relations) but that only applies to `entries` field, not matrix, and neither does it allow filtering on the related entity.

**Tags:** matrix, field, search
> **Comments:**
> **username_1**: I'd seriously question the use of a matrix field for that sort of data - sounds like all of those values will be required for each entry and moving them to their own fields would make those searches a lot simpler.  
> **username_2**: @Adam you're right, it is a lot simpler to filter entries by direct fields, but this shouldn't be a reason to decide against Matrix. You probably missed that the OP mentioned that each of these entries "campaigns" got multiple (maybe even optional) Matrix blocks "Travel dates".  
> **username_1**: @carlcs you're right, I had missed the potential for multiple dates - apologies  

---

## 3 answers

### Answer by username_2 on 2015-04-08. Score: 4 | Accepted answer

What I've done in a comparable situation is to add a hidden field to that entry type. And then I save Matrix data to that field on every save by listening to onBeforeSaveEntry events.
This makes the access to such processed Matrix data in templates or other parts of your plugin (i.e. getEntryTableAttributeHtml) very easy.
Event handler
craft()->on('entries.onBeforeSaveEntry', function(Event $event)
{
    $entry = $event->params['entry'];

    if($entry->section['handle'] == 'campaigns')
    {
        $longTravels = false;

        foreach ($entry->travelDates as $travelDate)
        {
            $duration = $travelDate->startDate->diff($travelDate->endDate);

            if ($duration > new DateInterval('P30D') && $duration < new DateInterval('P60D'))
            {
                $longTravels = true;
                break;
            }
        }

        // Set value for hidden field 'longTravels'
        $entry->getContent()->longTravels = $longTravels;
    }
});

CSS for hidden field type
{% set hiddenField %}
    #fields-{{ id }}-field {
        display: none;
    }
{% endset %}

{% includeCss hiddenField %}

> **Comments:**
> **username_5**: Along this route, you also might want to check out the [Preparse Field](https://github.com/aelvan/Preparse-Field-Craft) plugin – it sure helped me fetch the relevant data that was stored within a matrix.  
> **username_2**: @Avantlalettre good suggestion, I think I wrote this answer before the Preparse plugin existed. Today, I use Preparse a lot for these kind of things. You might want to post your comment as a separate answer though, it’s a bit burried in all this text and code. I’d definitly upvote it (and accept, if it was my decision :D).  

---

### Answer by username_3 on 2015-04-08. Score: 2

Yeah you are probably better off putting the startDate, endDate, and price in non matrix fields.  But if you don't something like this should probably work:
{# Get your list of entries (you probably don't want to start with all  entries, this is just an example #}
{% for entry in entries %}
    {# get the matrix field you want to sort things with #}
    {% for block in entry.yourTravelMatrix %}
        {# get the matrix block by type #}
        {% if block.type == "startDateBlock" %}
            {# set a variable to be the date in the field  #}
            {% set startDateVariable = block.startDateField %}
            {# use the variable to filter the entries #}
            {% if startDateVariable >= (now | date_modify("+1 months") %}
                {# whatever data you want to show from the entries #}
                {{ entry.title }}
            {% endif %}
        {% endif %}
    {% endfor %}
{% endfor %}

You'll probably have to adjust it a bit since dateTime fields are different than plain text fields.  There may be a better way to filter by a Matrix field.  Filtering by fields that aren't in a matrix is a lot easier.  This should basically work though.

> **Comments:**
> **username_0**: Thanks @jason. We share the thought. However there's a small issue with this approach. I cannot paginate the result set, which is quite long.  

---

### Answer by username_4 on 2015-06-09. Score: 1

I would like to propose something similar to this as a potential solution:
{# Matrix Search - Reasonably Elegant Solution #}

{# Initialise Matrix Block Owner IDs array #}
{% set matrixBlockOwnerIds = [] %}

{# This seems to be the easiest way to get the criteria in the shortest route #}
{% set ecm = craft.entries.section('mySectionHandle').type('myEntryTypeHandle').first().someMatrixBlockTypeHandle %}

{# Reset the owner ID because it was set by the first search #}
{% do ecm.setAttribute('ownerId', NULL) %}

{# Up the limit for a test - can be removed #}
{% do ecm.setAttribute('limit', 1000) %}

{# Set some search criteria #}
{% do ecm.setAttribute('startDate', '>= 2015-06-01') %}
{% do ecm.setAttribute('endDate', '<= 2015-07-01') %}

{# Find matching blocks #}
{% set matrixBlocks = ecm.find() %}

{# Iterate blocks and extract owner IDs (entry IDs) #}
{% for block in matrixBlocks %}
    {% set matrixBlockOwnerIds = matrixBlockOwnerIds|merge([block.ownerId]) %}
{% endfor %}

{# Query the entries by ID #}
{% set entries = craft.entries.find({'id': matrixBlockOwnerIds}) %}

{# Iterate entries #}
{% for entry in entries %}
    {{ entry.title }}
    {# Unfortunately we need to get the matrix blocks again, but this will include all blocks for the entry of that type #}
    {% for block in entry.someMatrixBlockTypeHandle.find() %}
        {# Output some block values #}
        {{ block.valueA }} - {{ block.valueB }}
    {% endfor %}
{% endfor %}

This isn't exact to your needs but I'm pretty sure it can be adjusted.
You can also do this for numeric ranges: 
{% do ecm.setAttribute('someNumericValue', ['and', '> 10', '< 20') %}

If you need to combine AND and OR for the same field you'd have to repeat the search with the 'and' set to or, but not reset the matrixBlockOwnerIds array ..
e.g.
{% do ecm.setAttribute('someNumericValue', ['and', '> 10', '< 20') %}

{% set matrixBlocks = ecm.find() %}

{% for block in matrixBlocks %}
    {% set matrixBlockOwnerIds = matrixBlockOwnerIds|merge([block.ownerId]) %}
{% endfor %}

{% do ecm.setAttribute('someNumericValue', ['and', '> 10', '< 20') %}

{% set matrixBlocks = ecm.find() %}

{% for block in matrixBlocks %}
    {% set matrixBlockOwnerIds = matrixBlockOwnerIds|merge([block.ownerId]) %}
{% endfor %}

If you need any help with these examples, just give me a message.


---

