Extension, Module

Archived
Forum
(read-only)

Stash

ExpressionEngine 2, ExpressionEngine 3, ExpressionEngine 4, ExpressionEngine 5, ExpressionEngine 6

Back to this add-on's main page
View Other Add-ons From Mark Croxton

     

Simulating “group by” filtering and sorting.

Support Request

Jannis Gundermann
Jannis Gundermann

Hi Mark,

I have a triathlon race listing, each member’s race results are stored inside a “event_data” channel, while the general event listing itself (name, location, etc…) is inside the “events” channel.

The URL will give me the entry_id of the event, which I use to filter down the event_data entries down to only the ones relevant to the current page.

This part all works.

Now, within the race results, I’ve got multiple fields to capture time data and also the race distance (text field).

Example:

Result 1:
Distance IM
Total    
[time in ms]

Result 2
:
Distance STN
Total    
[time in ms]

… 

The results should output in individual tables, one for each distance and within this table I need to sort by the total time.

Here is what I’ve got so far:

The first entries loop currently only collects all Distances so I can use unique=‘yes’ to grab those (in hopes of building a loop out of these).

The second loop is where the race results are stored in a list alongside the username and distance to be output in the result table.

{!-- Grab all possible distances for this event. --}
{exp
:stash:set_list name="@:race_distances" parse_tags="yes" parse_depth="5"}
  {exp
:channel:entries
    channel
="events"
    
entry_id="{segment_3}"
    
dynamic="no"
    
show_expired="yes"
    
show_future_entries="no"
    
parse="inward"
  
}
    {exp
:playa:parents
      channel
="event_data"
      
entry_id="{entry_id}"
      
show_expired="yes"
      
parse="inward"
      
search:cf_event_data_user_id="{stash:event_user_tags}"
      
orderby="cf_event_data_total"
      
sort="asc"
    
}
      {stash
:distance}{cf_event_data_distance}{/stash:distance}
    {
/exp:playa:parents}
  {
/exp:channel:entries}
{
/exp:stash:set_list}

{
!-- Build the result table --}
{exp
:stash:set_list name='@:table_body' parse_tags="yes" parse_depth="5"}

  {exp
:channel:entries
    channel
="events"
    
entry_id="{segment_3}"
    
dynamic="no"
    
show_expired="yes"
    
show_future_entries="no"
    
parse="inward"
  
}
    {
!-- Event Details --}
    {stash
:date}{cf_event_date format="%m.%Y"}{/stash:date}
    {stash
:date_sort}{cf_event_date}{/stash:date_sort}
    {stash
:name_location}{cf_event_name}{cf_event_location}{/stash:name_location}
    {stash
:event_id}{entry_id}{/stash:event_id}

    {exp
:stash:set_list:nested name="@:user_data" parse_tags="yes"}
      {exp
:playa:parents
          channel
="event_data"
          
entry_id="{entry_id}"
          
show_expired="yes"
          
parse="inward"
          
search:cf_event_data_user_id="{stash:event_user_tags}"
          
orderby="cf_event_data_total"
          
sort="asc"
        
}
          {stash
:user}{cf_event_data_user_id}{cf_user_first_name}{/cf_event_data_user_id}{/stash:user}
          {stash
:data_user_id}{cf_event_data_user_id var_prefix="data"}{data:entry_id}{/cf_event_data_user_id}{/stash:data_user_id}
          {stash
:race_country}{cf_event_data_user_id}{cf_user_race_country:alpha3}{/cf_event_data_user_id}{/stash:race_country}
          {stash
:distance}{cf_event_data_distance}{/stash:distance}
          {stash
:swim}{cf_event_data_swim}{/stash:swim}
          {stash
:t1}{cf_event_data_t1}{/stash:t1}
          {stash
:cycle}{cf_event_data_cycle}{/stash:cycle}
          {stash
:t2}{cf_event_data_t2}{/stash:t2}
          {stash
:run}{cf_event_data_run}{/stash:run}
          {stash
:total}{cf_event_data_total}{/stash:total}
        {
/exp:playa:parents}
    {
/exp:stash:set_list:nested}

  {
/exp:channel:entries}

{
/exp:stash:set_list} 

Output in template:

{exp:stash:get_list name='@:table_body'
  
orderby="distance,total"
  
sort="desc"
  
prefix="times"
  
parse_tags="yes"
}

{if times
:count == 1}
<table cellpadding="0" cellspacing="0" border="0">
  <
tr>
    <
th colspan="3"><date>{date}</date{name_location}</th>
    <
th>Distance</th>
    <
th>Swim</th>
    <
th>T1</th>
    <
th>Cycle</th>
    <
th>T2</th>
    <
th>Run</th>
    <
th>Total</th>
  </
tr>
{/if}

  {exp
:stash:get_list:nested name="@:user_data" prefix="result" orderby="distance, total" sort="desc"}
  
<tr data-mate-id="{data_user_id}"{if "{data_user_id}" == "{stash:user_id}"class="ht-row"{/if}>

    <
td class="t-left">{result:count}</td>
    <
td class="t-left">{user}</td>
    <
td>{race_country}</td>
    <
td>{distance}</td>
    <
td>{exp:timestring ms="{swim}"}</td>
    <
td>{exp:timestring ms="{t1}"}</td>
    <
td>{exp:timestring ms="{cycle}"}</td>
    <
td>{exp:timestring ms="{t2}"}</td>
    <
td>{exp:timestring ms="{run}"}</td>
    <
td>{exp:timestring ms="{total}"}</td>

  </
tr>
  
{/exp:stash:get_list:nested}

{if times
:count == times:total_results}
</table>
{/if}

{
/exp:stash:get_list} 

What I’m not sure how to do is break each distance into it’s own separate table.

Any thoughts would be appreciated.

Mark Croxton
# 1
Developer
Mark Croxton

There’s no need to run channel entries twice - you can just use the same list. To simulate ‘group by’ you need to:

1. Iterate over an array of unique distances in the list

2. For each distance output a table of events data for the matching distance

{!-- create a list containing only those columns that must be unique --}
{exp
:stash:set_list name="@:distance" parse_tags="yes"}
{exp
:stash:get_list name='@:table_body'
  
orderby="distance"
  
sort="desc"
 
}
{stash
:distance}{distance}{/stash:distance}
{
/exp:stash:get_list}
{
/exp:stash:set_list}

{exp
:stash:get_list name='@:distance' unique="yes"}

<table cellpadding="0" cellspacing="0" border="0">
<
caption>Results for {distance}</caption>
  <
tr>
    <
th>Distance</th>
    <
th>Swim</th>
    <
th>T1</th>
    <
th>Cycle</th>
    <
th>T2</th>
    <
th>Run</th>
    <
th>Total</th>
  </
tr>

{exp:stash:get_list:nested name="@:table_body" prefix="result" orderby="total" match="#^{distance}$#" against="distance"}

  
<tr data-mate-id="{data_user_id}"{if "{data_user_id}" == "{stash:user_id}"class="ht-row"{/if}>

    <
td class="t-left">{result:count}</td>
    <
td class="t-left">{user}</td>
    <
td>{race_country}</td>
    <
td>{distance}</td>
    <
td>{exp:timestring ms="{swim}"}</td>
    <
td>{exp:timestring ms="{t1}"}</td>
    <
td>{exp:timestring ms="{cycle}"}</td>
    <
td>{exp:timestring ms="{t2}"}</td>
    <
td>{exp:timestring ms="{run}"}</td>
    <
td>{exp:timestring ms="{result:total}"}</td>

  </
tr>

{/exp:stash:get_list:nested}

</table>
{/exp:stash:get_list} 

Note that you can capture the race meta data (name /date) as ordinarily stash vars in the same channel entries tag where you create the original list.

Jannis Gundermann
# 2
Jannis Gundermann

Thanks a lot Mark!

This made it all work.