I am trying to make a bibliography, by looping over a collection of .yaml files saved in a folder “data/articles”. Each of these files corresponds to one article and contains different variables such as “title” and “author”. For example, the file Lewis-2024.yaml looks like:
type: article
title: "One of the best articles in the world"
author: Lewis
year: 2024
When I use the following to make a list of available titles, everything works:
{{ range .Site.Data.articles }}
<p>Title: {{ .title }}</p>
{{ end }}
However, when I try to filter this list, the following commands do not seem to work:
{{ range first 10 .Site.Data.articles }}
<p>Title: {{ .title }}</p>
{{ end }}
{{ range where .Site.Data.articles "Params.author" "Lewis" }}
<p>Title: {{ .title }}</p>
{{ end }}
This is really puzzling, as this looks like a trivial example and I am following the examples of the documentation (e.g., where | Hugo for the second one). I must be missing something very basic here… Any clue?
Yes, I have edited my initial question with more details. “articles” is a folder that contains several .yaml files. I am providing a simplified example of such a file here. In my project each of these files contains a lot of information, that’s why I prefer keeping them as separate files instead of one single file. Thank you for your help.
Running hugo server --verbose in the terminal provides the following error (for the example with first 10):
ERROR 2018/09/29 17:12:26 Error while rendering "section" in "bibliography/": template: bibliography/section.html:16:9: executing "main" at <first 10 $.Site.Data....>: error calling first: can't iterate over map[string]interface {}
WARN 2018/09/29 17:12:26 template: bibliography/section.html:16:9: executing "main" at <first 10 $.Site.Data....>: error calling first: can't iterate over map[string]interface {}
I guess that it works in the original example because range can loop over a map (which I seem to be dealing with here), while first and where can only work with an array.
Is this the explanation? (Slowly learning here, sounds counter-intuitive at first… if it is possible to loop over a map, why not also loop with conditions?) If yes, what would be a simple fix?
… that needs some more debugging. range over .Site.Data.articles works, as it is a collection. But first should work too, as it iterates over the same collection. Try to print the content of this collection to the screen:
Now that I know where to look, the problem becomes more obvious. There have been many posts about this, see e.g. here.
What still puzzles me is that blog posts are usually saved as individual files in a content folder, and then the functions range can be used together with first and where to create appropriate lists. What is so different here? Why is a map produced, which cannot be processed by these two functions?
The {{ printf "%#v" .Site.Data.articles }} you suggested produces something like this:
map[string]interface {}{"one_article":map[string]interface {}{"type":article, "title":"Best article of the world", "author"="Lewis"}, "another_article":map[string]interface {}{"type":article, "title":"Second best article of the world", "author"="Lewis"}, "another_one":map[string]interface {}{"type":article, "title":"Yet another article", "author"="John"}}
@remek Can you possibly link us to the full source for the project? I have some ideas on how to help but it will be much easier to run it locally. If you’re worried about a private project, please feel free to DM as well. Thanks!
This makes sense in the context of first, as you want to reliably retrieve the first n elements of a slice. As the content of a map is rather random, first would do the same as any (if that function would exist), as you don’t know which elements come back. I don’t understand, why where would need a sorted data array, as a mixed map would suffice, but that is another topic.