Hugo “in slice” versus union queries

As you may remember, I use Hugo sections to structure my site content, and that affects my queries for things like site comprehensive RSS feed and my “Things I’ve written” section, which shows all posts from every section.

The way I have my site set up is that I have several blog sections, starting with Blog, which currently has 3 posts in it that don’t fall under other sections, and then under Blog I have subsections for iOS, Mac, Hugo, and Apple history. Finally, I have a Podcasts section at the same level as Blog.

Podcasts is mostly unused at the moment as it’s where I’m going to make repositories of past (inactive) podcasts, as well as descriptions and links to current and (and future current) podcasts. However, I’ll also post in that section about different episodes of things I’m in.

Anyway, it looks like this, or will look like this:

 | apple history
 | hugo
 | ios
 | mac
 | current podcast 1
 | current podcast 2
 | past podcast 1
 | past podcast 2

On the site home page, I currently have it set up to display the most 3 recent posts with a list of the 5 posts prior to that, followed by a link to Blog. When I say the 3 most recent posts, that means the 3 most recent from any of the sections listed above.

Similarly, when people go to the “Things I wrote” page (/blog), I display all posts from each of the above sections, 10 posts per page.

All of these posts should be in chronological order, most recent first, regardless of the section they’re in. So if my most recent post is in the Hugo section (/blog/hugo), that should be the first post on page 1 of “Things I wrote”. Then if the second most recent is in Podcasts (/podcasts), that should be the second post on page 1.

In order to display posts from all the different sections, you need to create a query more complicated than range .RegularPages.

I found some examples that used union to grab posts from different types or sections, so I was using the following query for the site RSS feed, the home page, and the “Things I Wrote” (blog) section:

{{ $pages := where .Site.RegularPages "Section" "blog" }}
{{ $pages := $pages | union (where .Site.RegularPages "Section" .Sections )}}
{{ $pages := $pages | union (where .Site.RegularPages "Section" "podcasts") }}
{{ range $pages.ByDate.Reverse }}
{{ end }}

I thought this was great and dandy except that I started noticing on both the home page and blog page, sometimes things would be out of order or I wouldn’t see things in the lower list of 5 posts on the home page. It seemed like it always had to do with things that were under Podcasts, so grouping was my first suspect. My union query was taking three queries and stuffing them together, and my guess is that there was some sub-grouping going on based on that fact.

What I should have done instead, and am in fact now doing, is doing one query with one “where” clause using “where in slice”:

{{ $pages := where .Site.RegularPages "Section" "in" (slice "blog" .Sections "podcasts") }}
{{ range $pages.ByDate.Reverse }}
{{ end }}

Or in the case of Blog, which is paginated:

{{ $paginator := .Paginate (where .Site.RegularPages "Section" "in" (slice "blog" .Sections "podcasts")) 10 }}
{{ range (.Paginator 10).Pages.ByDate.Reverse }}
{{ .Render "summary" }}
{{ end }}

The slice may be a little confusing because of the center element, .Sections.

where .Site.RegularPages "Section" "in" (slice "blog" .Sections "podcasts")

It actually works like my union query did where I was joining three queries where something was in section blog, or in .Sections, or in section podcasts.

Coming after the section named “blog”, .Sections grabs posts in the subsections of blog.

The bottom line is when you want to mix posts from different sections chronologically and have them all mixed in by date without regard to section grouping, don’t use union to join queries together. Use one query, and query for things in your slice of section names.