Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

groupby complex attributes #1198

Closed
tcurdt opened this issue Mar 10, 2019 · 8 comments · Fixed by #1276 · 4 remaining pull requests
Closed

groupby complex attributes #1198

tcurdt opened this issue Mar 10, 2019 · 8 comments · Fixed by #1276 · 4 remaining pull requests

Comments

@tcurdt
Copy link

tcurdt commented Mar 10, 2019

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?

@mattradford
Copy link

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

@mattradford
Copy link

@tcurdt This may help: https://stackoverflow.com/questions/12764291/jinja2-group-by-month-year

@tcurdt
Copy link
Author

tcurdt commented Mar 18, 2019

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

@justinfagnani
Copy link

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;
      };
    }

@tcurdt
Copy link
Author

tcurdt commented Jan 29, 2020

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

@justinfagnani
Copy link

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 %}

@anaurelian
Copy link

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

@tcurdt
Copy link
Author

tcurdt commented Apr 7, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment