Nunjucks: groupby complex attributes

Created on 10 Mar 2019  路  8Comments  路  Source: mozilla/nunjucks

I have a list of objects. These objects have a date attribute. I want to group by year.
Something along the lines of the following would be nice.

for year, posts in collections.post | groupby("date.year")

But it begs the question how to deal with transforms that need to happen before the grouping.
Is there a way to use groupby like this?

Most helpful comment

This is a filter I'm using for Nunjucks in Eleventy:

groupByEx: function (arr, key) {
    const result = {};
    arr.forEach(item => {
        const keys = key.split('.');
        const value = keys.reduce((object, key) => object[key], item);

        (result[value] || (result[value] = [])).push(item);
    });
    return result;
}

Sample (actual) usage:

for categoryName, articles in productArticles | groupByEx("data.categoryName")

Acknowledgement: Code based on whatterz/includes.js

All 8 comments

Oh man, this is exactly the problem I'm trying to solve.

@mattradford That's exactly what I was referring to with date.year above ;) Unfortunately that does not work (for me).

Looking at the underlying groupBy code here: https://github.com/mozilla/nunjucks/blob/master/nunjucks/src/lib.js#L172

It takes a function, so you can write a generic getPath function that returns a function to get the value you want to group on. Just verified that this works. Here's my getPath:

    const getPath = (path) => {
      const parts = path.split('.');
      return (value, i) => {
        let o = value;
        for (const p of parts) {
          if (o == null) {
            return;
          }
          o = o[p];
        }
        return o;
      };
    }

@justinfagnani The function is straight forward - but the question is how this should look like in the expression.

The depends on how you get the function as data into your template. I'm using eleventy, and putting the function into a docs object. My template looks like:

{% for group, examples in collections.examples | groupby(docs.getPath('data.group')) %}
...
{% endfor %}

This is a filter I'm using for Nunjucks in Eleventy:

groupByEx: function (arr, key) {
    const result = {};
    arr.forEach(item => {
        const keys = key.split('.');
        const value = keys.reduce((object, key) => object[key], item);

        (result[value] || (result[value] = [])).push(item);
    });
    return result;
}

Sample (actual) usage:

for categoryName, articles in productArticles | groupByEx("data.categoryName")

Acknowledgement: Code based on whatterz/includes.js

@anaurelian that's already pretty slick - but it would need a special case for dates I guess.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kamlekar picture kamlekar  路  5Comments

sudhirbeldar picture sudhirbeldar  路  3Comments

boutell picture boutell  路  6Comments

kud picture kud  路  3Comments

gaboesquivel picture gaboesquivel  路  4Comments