Range over Site Data or getJSON using where

I have some JSON structures that get updated annually and I have a working shortcode to display slices of that data

{{ $url := "/data/rallies.json" }}
{{ $year := .Get "year" }}
{{ range $rally := getJSON $url }}
{{ if and (eq $rally.year $year) (ne $rally.awards nil) }}
//do stuff with $rally.awards
{{ end }}
{{ end }}

Now I’m trying to improve it by using where on the range

{{ $url := "/data/rallies.json" }}
{{ $year := .Get "year" }}
{{ range where (getJSON $url) $.year $year }}
{{ $rally := . }}

The error I’m getting proves that the getJSON part returns the correct data but I think it’s failing on the 2nd parameter to where

ERROR: 2016/03/15 error processing shortcode shortcodes/awards.html
 ERR: template: shortcodes/awards.html:3:31: executing "shortcodes/awards.html" at <$.year>: year is not a field of struct type *hugolib.ShortcodeWithPage
WARN: 2016/03/15 &{map[year:1985]   true}

Trye .year instead of $.year

Still no joy, basically the same message

ERROR: 2016/03/16 error processing shortcode shortcodes/awards.html
 ERR: template: shortcodes/awards.html:3:30: executing "shortcodes/awards.html" at <.year>: year is not a field of struct type *hugolib.ShortcodeWithPage
WARN: 2016/03/16 &{map[year:1985]   true}

OK, the second argument to where should be the property name, so a string (“year”).

Yeah I tried that too (and also with a dot prepended) which gives this error:

ERROR: 2016/03/16 error processing shortcode shortcodes/awards.html
 ERR: template: shortcodes/awards.html:3:9: executing "shortcodes/awards.html" at <where (getJSON $url)...>: error calling where: can't iterate over map[string]interface {}
WARN: 2016/03/16 &{map[year:1996]   true}

Yes, that is a restriction with with. You will have to look at your JSON and see if you can refactor it or use parts of it that is a list and not a dictionary.

Yep awesome, that works with the following JSON data:

[
  {
    "awards": [
      {
        "award": "Club Person of the Year",
        "recipients": [
          "Winner Name"
        ]
      }
    ],
    "year": "1968"
  }
]

and shortcode:

{{ $url := "/data/test.json" }}
{{ $year := .Get "year" }}
{{ range where (getJSON $url) "year" $year }}
{{ $rally := . }}
    {{ range $award := $rally.awards }}
        <div>{{ $award.award }}</div>
        <div>{{ range $recip := $award.recipients }}{{ $recip }}<br/>{{ end }}</div>
    {{ end }}
{{ end }}

called from a markdown page as

{{< awards year="1968" >}}

Interestingly, it works with either ".year" or "year" as the 2nd parameter to where.

Now for the cherry on top: I only want where to return data where the year matches AND $rally.awards is present and not empty. Is that possible?

@tatsushid may arrest me, but I think the only way to add multiple conditions is to nest the where filters:

{{ range where (where (getJSON $url) "year" $year) ... }}

On an added note, if you have your JSON inside /data you don’t need the getJSON func, you can just do:

{{ range where $.Site.Data.test "year" $year }}
1 Like

Correction:

{{ $year := .Get "year" }}
{{ range where (where $.Page.Site.Data.rallies "year" $year) "awards" "ne" nil }}
{{ $rally := . }}

gets data from data/rallies.json the way I want it.

Thanks for your help and for the tip :smile:

1 Like

And just for completeness, this is the map version of what I was trying to achieve (where the JSON data is key-value instead of array), for example:

{
  "1968": {
    "awards": [
      {
        "award": "Club Person of the Year",
        "recipients": [
          "Winner Name"
        ]
      }
    ]
  }
}
{{ $year := .Get "year" }}
{{ $rally := (index $.Page.Site.Data.rallies $year) }}
{{ with $rally.awards }}
.. do something with awards if it exists
{{ end }}

and that can be distilled down to

{{ $year := .Get "year" }}
{{ with (index $.Page.Site.Data.rallies $year).awards }}
.. do something with awards if it exists
{{ end }}
1 Like