I'm using node.js and MongoDB to create an app. I have 2 collections and you could say that they are in a 1:N relation.
col1 = { id="abc", name="London", createdAt=... }
col2 = { id="..." link="abc", temperature=31.24, sentAt=... }
I would like to create a table that would display it's name and temperature (the latest one, because there could be more)
Name | Temperature
London | 31.24
So I'm passing both objects from MongoDB into nunjucks where I'm trying to cycle through them like so:
{% for city in col1 %}
{% for data in col2 %}
{{ city.name }} | {{ data.temperature }}
{% endfor %}
{% endfor %}
But if I do this the result is this:
Name | Temperature
London | 31.24
London | 31.24
And I know why that is but I don't really know how to fix it and I think that it has to have some common way to fix this.
{% set data = {} %}
{% for city in col1 %}
{% for data in col2 %}
{% set data[city.name] = data.temperature %}
{% endfor %}
{% endfor %}
{% for city, temperature in data %}
{{city}} | {{temperature}}
{% endfor %}
But the best way is uniqued values outside of nunjucks template.
Related
I'm trying to create 3 arrays of propducts which are created based on a timestamp.
I'm working on a SaaS platform so I have to create those arrays in the frontend while creating a function in the backend would be better but that's not possible.
The idea is to create 3 arrays for a lottery. So 1 is for current lotteries, 1 for upcoming ones and 1 for recent lotteries.
The problem I have is that it won't sort correctly. So for example the oputput shows 24th of april before 24th of March.
So what I have is this:
{% set curr_date = "now"| date('U') %}
{% set current_draws = [] %}
{% set upcoming_draws = [] %}
{% set recent_draws = [] %}
{% for product in products %}
{% if product.data_01 %}
{% set data_01_date = product.data_01 | date('U') %} //make timestamp for this product
{% if data_01_date > curr_date %} //check if is upcoming or current
{% if loop.first %} //if 1st in loop then it's current draw
{% set current_draws = current_draws | merge([product]) %}
{% else %}
{% set upcoming_draws = upcoming_draws | merge([product]) | sort((a, b) => a.data_01_date <=> b.data_01_date ) | reverse %}
//reverse because lowest timestamp need to be showed first
{% endif %}
{% else %}
{% set recent_draws = recent_draws | merge([ product ]) | sort((a, b) => a.data_01_date <=> b.data_01_date ) %}
{% endif %}
{% endif %}
{% endfor %}
As output for the upcoming draws array I get the following:
{% for product in upcoming_draws %}
{{ product.data_01 | date("U") }}
{% endfor %}
1648162800 // 25th March
1650751200 // 24th April
1648249200 // 26th March
1648335600 // 27th March
Why in above example is 24th of April showed before 26th of March?
Any idea how to fix that?
Any help greatly appreciated :)
Three things:
You have a typo, the property is called data_01, as seen here {% set data_01_date = product.data_01|date('U') %}
Don't sort the array during the creation of the array, that's a waste of performance
The property data_01 is a string, you shouldn't compare strings in your sort
{% set curr_date = "now"| date('U') %}
{% set current_draws = [] %}
{% set upcoming_draws = [] %}
{% set recent_draws = [] %}
{% for product in products %}
{% if product.data_01 %}
{% set data_01_date = product.data_01 | date('U') %} //make timestamp for this product
{% if data_01_date > curr_date %} //check if is upcoming or current
{% if loop.first %} //if 1st in loop then it's current draw
{% set current_draws = current_draws | merge([product]) %}
{% else %}
{% set upcoming_draws = upcoming_draws | merge([product]) %}
//reverse because lowest timestamp need to be showed first
{% endif %}
{% else %}
{% set recent_draws = recent_draws | merge([ product ]) %}
{% endif %}
{% endif %}
{% endfor %}
{% for product in upcoming_draws|sort((a, b) => a.data_01|date('U') <=> b.data_01|date('U') | reverse ) %}
{{ product.data_01 | date("d-m-Y") }}
{% endfor %}
demo
I have a for-loop within another for-loop and I would like the inner for-loop to go through the array test[INDEX] with [INDEX] being the index of the outer for-loop. I know I can get the loops index with the variable {{ loop.index() }}, however I do not know how to apply that within the head of my inner loop.
I've tried {% for x in test.{{ loop.index0 }} %}, but that throws me the error
Expected name or number.
Is there any way to do this?
In twig you can also use the array notation to get values from a variable
A note here is that the default loop.index is 1 indexed so you might want to use loop.index0 to get the correct offset
{% for f in foo %}
- {{ f }}: {{ bar[loop.index0] }}
{% endfor %}
As an alternative you can also get the key in the {% for key, value ... format
{% for key, value in foo %}
- {{ value }}: {{ bar[key] }}
{% endfor %}
demo
edit
As for you comment, you can succesfuly use this in any inner-loop, here is a more readable example
{% for country in countries %}
{{ country }}:
{% if cities[loop.index0]|default %}
<ul>
{% for city in cities[loop.index0] %}
<li>{{ city }}</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
demo
In Craft CMS, I have child entries where each child has a location with "city" and "country" values assigned to it.
I'm looking to output a list of "City, Country" text but remove any duplicates as two or more children might share the same "city,country" pair.
It's important that I can reference the city and country value for each child separately, because I need to use the country value for displaying a flag for each child item in the list.
I've learned about and tried my hand at "twig hash" and "associative arrays" and found usable snippets but can't make it work together for my case.
This does not work:
{% set children = entry.children %}
{% set locations = {} %}
{% for child in children %}
{% set city = child.location.parts.locality %}
{% set country = child.location.parts.country %}
{% if city not in locations %}
{% set locations = locations|merge({ city : country }) %}
{% endif %}
{% endfor %}
{% for location in locations %}
{% for k, v in location %}
{{ k }}, {{ v }} <br />
{% endfor %}
{% endfor %}
If you want to let the city be the key of your array you will need to wrap them in parantheses so the variable will get interpreted by twig.
Also you don't need the double for loop, you are building a one dimensional array
{% set locations = {} %}
{% for child in children %}
{% set city = child.city %}
{% set country = child.country %}
{% if city not in locations %}
{% set locations = locations|merge({ (city) : country }) %}
{% endif %}
{% endfor %}
{% for k,v in locations %}
{{ k }}, {{ v }} <br />
{% endfor %}
demo
sort does not work here
{% for key, season in seasons | sort %}
but does here
{% for episode in season | sort %}
here is the entire twig snippet
{% for key, season in seasons | sort %} {# <<this is the sort not working #}
<button class="accordion"><h5>Season {{ key }}</h5></button>
<div class="panel">
{% for episode in season | sort %}
<li><h5><b>{{ episode.title }}</b></h5></li>
{% endfor %}
</div>
{% endfor %}
If you need reverse sort use this.
{% for key, season in seasons |sort((a, b) => a.id <= b.id) %}
{% for episode in season | sort %}
{{ episode.title }}
{% endfor %}
{% endfor %}
You juste need add in your for this code.
|sort((a, b) => a.id <= b.id)
Jekyll pagination enables you to arrange posts neatly on pages. I would like to put the range of dates as a tooltip on the links to the pages, just as:
<li class="pager-item">
Page 2
</li>
The obvious way to do so would be to take the date of the first and the last post on a page. Unfortunatly jekyll-pagination only seems to deliver a list of posts for the current page via paginator.posts.
Maybe I just can't find it in the documentation, so I ask you: is it possible to access a list of posts from another page in jekyll pagination? Something like paginator.pages.2.posts?
An alternate approach would be to build my own paginaton, which should be no problem, but I would prefer to use built-in functions.
You can get the information indirectly:
paginator.previous_page and paginator.next_page give you the page number of respectively the previous and the next pagination page, or nil if the page does not exists.
paginator.per_page gives you the number of posts per page.
paginator.total_posts gives you the total number of posts in the site.
site.posts gives you a reverse chronological list of all posts.
So given the current paginator object, ensuring paginator.next_page != nil, you know the posts from the next pagination page are indexed in site.posts from a to b (included) with:
a = (paginator.next_page) * paginator.per_page
b = a + paginator.per_page - 1
Last pagination page may not be complete: remember checking b < paginator.total_posts.
Ensuring paginator.previous_page != nil, same goes for previous pagination page with:
a = (paginator.previous_page) * paginator.per_page
b = a + paginator.per_page - 1
My current approach looks like this:
{% if include.page > 0 and include.page <= paginator.total_pages %}
{% assign first = include.page | minus:1 | times:paginator.per_page %}
{% assign last = paginator.per_page | times:include.page | minus:1 %}
{% if last > paginator.total_posts %}
{% assign last = paginator.total_posts | minus:1 %}
{% endif %}
{{ site.posts[first].date | date: "%d.%m.%Y" }} bis {{ site.posts[last].date | date: "%d.%m.%Y" }}
{% else %}
OUT_OF_RANGE
{% endif %}
I really don't like the Liquid-Syntax :D
Or :
{% comment %} NOTE : shortcut "p" for "paginator" {% endcomment %}
{% assign p = paginator %}
{% comment %} date formating (see shorthand formats in Ruby's documentation : http://ruby-doc.org/core-2.3.3/Time.html#method-i-strftime) {% endcomment %}
{% assign dateFormat = "%y %b %d" %}
<ul>
{% for post in p.posts %}<li>{{ post.title }} - {{ post.date | date: dateFormat }}</li>
{% endfor %}
</ul>
{% comment %}++++++++++ if previous page == newest posts {% endcomment %}
{% if paginator.previous_page %}
{% assign prevPage = p.page | minus: 1 %}
{% assign prevPageLastIndex = prevPage | times: p.per_page | minus: 1 %}
{% assign prevPageFirstIndex = prevPageLastIndex | minus: p.per_page | plus: 1 %}
{% assign prevPagefirstPostDate = site.posts[prevPageFirstIndex].date | date: dateFormat %}
{% assign prevPagenextPageLastPostDate = site.posts[prevPageLastIndex].date | date: dateFormat %}
{% capture prevPageLink %}
<p><a href="{{ paginator.previous_page_path }}"></p>
Newest posts from
{% if prevPagefirstPostDate != prevPagenextPageLastPostDate %}
{{ prevPagenextPageLastPostDate }} to {{ prevPagefirstPostDate }}
{% else %}
{{ prevPagenextPageLastPostDate }}
{% endif %}
</a>
{% endcapture %}
{% endif %}
{% comment %} ++++++++++ if next page = oldest posts {% endcomment %}
{% if paginator.next_page %}
{% assign nextPage = p.page | plus: 1 %}
{% assign nextPageFirstIndex = p.page | times: p.per_page %}
{% comment %}>>Next page is not the last page = normal computing {% endcomment %}
{% if nextPage != p.total_pages %}
{% assign nextPageLastIndex = nextPageFirstIndex | plus: p.per_page | minus: 1 %}
{% comment %}>>Next page is the last page compute index from p.total_posts{% endcomment %}
{% else %}
{% assign nextPageLastIndex = p.total_posts | minus: 1 %}
{% endif %}
{% assign nextPagefirstPostDate = site.posts[nextPageFirstIndex].date | date: dateFormat %}
{% assign nextPageLastPostDate = site.posts[nextPageLastIndex].date | date: dateFormat %}
{% capture nextPageLink %}
<p><a href="{{ paginator.next_page_path }}"></p>
Previous posts from
{% if nextPagefirstPostDate != nextPageLastPostDate %}
{{ nextPageLastPostDate }} to {{ nextPagefirstPostDate }}
{% else %}
{{ nextPageLastPostDate }}
{% endif %}
</a>
{% endcapture %}
{% endif %}
{{ prevPageLink }}
{{ nextPageLink }}