Group YAML entries in data file by date

Is there a date filter which will group all items on a given date under one element?

I have a a page with a series of links - populated from a YAML file - and want to only add a date above the first item of each day. Existing code is as follows.

{% for link in site.data.links %}
  <h2><a href="{{ link.url }}">{{ link.title }}</a></h2>
  <br />
  <span>{{ link.content }}</span>
<hr />
{% endfor %}

Does Liquid have the concept of something like the :first-child selector in CSS so I could insert the date at that point?

What does the data look like in your YAML file? You’ll likely need some logic inside of the for loop to group items.

Liquid does have some other ways at accessing object data that might be helpful.

1 Like

Nothing complicated. Basically a bunch of entries that look similar to this:

- title: New York Needed Ventilators. So They Developed One in a Month
  url: https://www.nytimes.com/2020/04/20/technology/new-york-ventilators-coronavirus.html
  content: Square peg in a round hole - rapidly.

Obviously, dates will get added to each of these, but I wanted to be sure I didn’t need to look elsewhere to get this done. forloop.first looks promising, will test to see if that does it.

Yes .first will work if you can first group into date and then items.

I have an idea which avoids grouping. First make sure your items are ordered by date time. Apply reverse filter if needed. I’m assuming descending order here.

Then iterate over with a single for loop.

At each iteration you check if the current date time is equal to the max of all the date times after filtering to current date only. That’s computationally expensive

Alternatively you can use a pair of variables and check when they differ as that means you’ve arrived a new day and not hit a repeat of yesterday. And it only takes a single pass over the array.

Writing psuedo code here. I treat everything as date time (well they can be strings as long as they have a date and time component) and only format as date once for output

# initial value to force printing first item and define the var.
previous_datetime = nil

for current in items
  if current.datetime != previous_datetime
    Date: {{ current.datetime | date 'Y M D' }}
  endif

  Time: {{ current.datetime | time }}  # show as H:M?
  Title: {{ current.title }}
  URL: {{ current.url }}

  # the current value becomes previous for the next iteration 
  previous_datetime = current.datetime
endfor

I decided to actually use a collection instead and just print the dates - These are kind of like posts, which themselves are really just a special collection in Jekyll.

With regard to @MichaelCurrin’s suggestion, I have also found this pattern works to achieve the effect I was looking for. I am using it to implement a “notes” section along with a couple other Indieweb features on my site.

I know the archives plugin is available, but this really is more of a running tally.

Edit: I stand corrected. YMMV, but the solution described above may not sort correctly with multiple items. I am now testing with the answer from user @Trevor in the same SO thread.

You may need to sort both loops in reverse order.

1 Like