How to use filter using where and .Site.Data?

Assuming our normal markdown pages have a is_featured field in the frontmatter, we can filter like this

{{ range where .Site.Pages ".Params.is_featured" true }}

… but how can you do the same with data pages? E.g. content stored in data/posts/my-post.yml.

I tried many combinations but couldn’t make it work. What’s the proper syntax?

{{ range where .Site.Data.posts ".Params.is_featured" true }}

Try:

range where .Site.Data.posts "is_featured" true
1 Like

Thanks, but it doesn’t return anything I’m afraid. See here:

I searched some more and found that the “Site.Data…” are technically maps — not arrays — which could explain why the where does not work… Pretty counter-intuitive, especially since range works fine. See:

Wouldn’t hugo want to support this feature? Maybe automagically map the maps into arrays when used together with where?

The method used to extract the desired data depends on the data structure, and there are an infinite number of possible structures. If you share a meaningful sample of your data, perhaps we can find a way to get what you need.

You’re right, my bad. Looks like so:

/data/spaces/test.yml

name: My title
is_featured: true

Assuming this directory structure:

data
└── spaces/
    ├── a.yaml
    ├── b.yaml
    └── c.yaml

You can get a better understanding of your data structure with:

<pre>{{ jsonify (dict "indent" "  ") site.Data }}</pre>

That renders this:

{
  "spaces": {
    "a": {
      "is_featured": true,
      "name": "a"
    },
    "b": {
      "is_featured": false,
      "name": "b"
    },
    "c": {
      "is_featured": true,
      "name": "c"
    }
  }
}

So to find the “names” that are “featured”…

{{ range site.Data.spaces }}
  {{ if .is_featured }}
    {{ .name }}
  {{ end }}
{{ end }}
4 Likes

Thanks so much for the detailed answer and nifty tip with jsonify.

The nested-if solution works. How would you get the length of “featured spaces” in your example? You’d have to iterate and append into a new array, correct?

Seems useful if hugo could support maps with range where directly. Less mental overhead if site.pages + site.data would parse the same way. Anyway, that’s a feature request.

They do parse the same way when they have the same top-level structure.

If you had created a single spaces.yaml file instead of separate files in a spaces directory:

- name: a
  is_featured: true
- name: b
  is_featured: false
- name: c
  is_featured: true

This:

<pre>{{ jsonify (dict "indent" "  ") site.Data }}</pre>

Produces this:

{
  "spaces": [
    {
      "is_featured": true,
      "name": "a"
    },
    {
      "is_featured": false,
      "name": "b"
    },
    {
      "is_featured": true,
      "name": "c"
    }
  ]
}

And then you can do this:

{{ range where site.Data.spaces "is_featured" true }}
  {{ .name }}
{{ end }}

Finally, if you have this structure:

data
└── spaces/
    ├── a.yaml
    ├── b.yaml
    └── c.yaml

and if the file names should not be part of the data structure, you can wrangle the array of nested maps into an array of maps with:

{{ $temp := slice }}
{{ range site.Data.spaces }}
  {{ $temp = $temp | append . }}
{{ end }}

That looks like this:

[
  {
    "is_featured": true,
    "name": "a"
  },
  {
    "is_featured": false,
    "name": "b"
  },
  {
    "is_featured": true,
    "name": "c"
  }
]

and then you can do:

{{ range where $temp "is_featured" true }}
  {{ .name }}
{{ end }}
1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.