Filtering data template objects in Hugo - json

So I'm trying to build a quick page listing event details with Hugo (first time working with it, so bear with me).
I've put the two categories of events into two JSON files and added them to /data/events/aevents.json and /data/events/bevents.json
Sample json
{
"devcon 1": {"evname": "Dev Con 1", "year": "2019", "date": "2020-05-12T23:29:49Z"},
"devcon2": {"evname": "Dev Con 1", "year": "2018", "date": "2018-05-12T23:29:49Z"}
}
Now when I use
{{ range .Site.Data.events.aevents }}
things work as expected.But they don't when I use
{{ range .Site.Data.events }}
which I thought would give me events from aevents.json and bevents.json.
Second part
The json events have a date property. When I try to filter to just show upcoming events, my list is blank. I've been playing with variants of this:
{{ range where .Site.Data.events.aevents "date" "ge" now }}
and have tried a bunch of different date formats. Any tips on where I might be going wrong?

First Part
The snippet:
{{ range .Site.Data.events }}
Will get you two objects - one for aevents and one for bevents. You will need to do a nested range to process the individual events in the two files.
{{ range .Site.Data.events }}
{{ range . }}
.....
Second Part
I don't think that can be done directly in the range so you will need to filter afterwards:
{{ range .Site.Data.events }}
{{ range . }}
{{ if .date > $date }}
...

Related

Liquid Map Arithmetic Operations

Hello wise people of StackOverflow,
I have an exchange rates file that I am mapping from XML to JSON in an Azure logic app using Transform XML To JSON. I have two rates (Ask and Bid) within the XML. A node in the XML file looks like so:
<quote>
<ask>110.0668027</ask>
<bid>108.1461645</bid>
<currency>AFA</currency>
<date>2022-07-27T23:59:59+0000</date>
<midpoint>109.1064836</midpoint>
</quote>
I then need to map to JSON but I wish for the JSON output to only show a single rate which must be calculated as (Ask+Bid)/2 to give me the average.
I have created a liquid map like so:
{
"EffectiveDate": "2022-06-06",
"BaseCurrency": "GBP",
"ExchangeRates":
[
{% for data in content.response.quotes %}
{
"ExchangeRate": "({{data.quote.ask}} + {{data.quote.bid}})/2",
"TargetCurrency": "{{data.quote.currency}}"
},
{%endfor%}
]
}
But when I run the logic app the JSON output looks like so:
{
"ExchangeRate": "(110.0668027 + 108.1461645)/2",
"TargetCurrency": "AFA"
},
Which is obviously not what I want to see! What is wrong with the syntax in my Liquid map?
In Liquid you have to use math filters to manipulate integers.
So I would do something like that:
First calculate your value to divide.
{% assign value_2 = value_2 | divided_by:2 %}
Then output your values by adding them:
{{ value_1 | plus: value_2}}
More info about math filters here: Documentation about math filters

"Cannot read property '0' of undefined" when reading environment variable from mongoDB

I am trying to read a variable which is defined in my javascript. It is a get request from a mongoDB. The whole database is then stored under a variable and is read by the HTML and displayed.
The get request from the MongoDB has an output like this:
(Lets say this is stored under the variable database):
[
{
0:
{
TITLE1: valueone
}
},
{
1:
{
TITLE2: valuetwo
}
}
]
My HTML looks like this:
<p> {{ database?.TITLE1 }} </p>
I get the error Cannot read property '0' of undefined. I understand this is because I need to define [0] to be able to read TITLE1.
Based on this I have tried the following:
<p> {{ database?[0].TITLE1 }} </p>
This has this error: Template parse errors:
Parser Error: Conditional expression database?[0].TITLE1 requires all 3 expressions at the end of the expression [{{ database?[0].TITLE1 }}]
<p> {{ database?.[0].TITLE1 }} </p>
This has this error: Template parse errors:
Parser Error: Unexpected token [, expected identifier or keyword at column 7 in [{{ database?.[0].TITLE1 }}]
<p> {{ database?.0.TITLE1 }} </p>
This has the same error as the one above.
What is the correct way to be able to read the values that I am after. In the HTML the output should be valueone.
Because your database is array, use need use [0] to get first item and your key is number so you need use ['0'] to get property value, you also can use ? to check object null before using TITLE1
Finally you can use {{ database[0]['0']?.TITLE1 }}
Demo https://stackblitz.com/edit/angular-o79rra
Well I mean, at some point you have to think a little about JS basics instead of trying everything until it works ...
From the code you have provided, the syntax would be
{{ data[0]['0'].TITLE1 }}
Try
<p> {{ database[0]['0']?.TITLE1 }} </p>
Do it dynamically by:
<p *ngFor="let item of database; let i = index">
{{item[i]['TITLE' + (i + 1)]}}
</p>

Get the value of a JSON array with _attribute

I have a strange looking JSON file (I think?) generated from elasticsearch.
I was wondering if anyone know how I could retrieve the data from a JSON object looking like this:
u'hits : {
u'hits : [{
u'_score' : 2.1224,
u'_source' : {u'content': u'SomethingSomething' }
}],
u'total: 8 }
u'took: 2 }
I can retrieve the total by writing {{ results.hits.hits.total }}, however, the underscore symbol (_) in front of the attribute name "_score" makes it impossible to retrieve the value of that attribute.
Any suggestions?
Try:
{{ results.hits.hits[0]._score }}
{{ results.hits.hits[0]._source }}

Combining two variables for use in Twig

I'm using Google app engine and I'm trying to set the value of a textarea based on the concatenation of two string variables. Let's say I have 4 items, and each item has multiple fields. So in my Python I'm passing the dictionary { 'value0': newValue }. I'm using a for loop (iterator value num) and I want to use in my HTML something equivalent to {{ value }}{{ num }} where the variable referenced is value0.
I've tried {{ value~num }} but nothing works. If I could use an array that would be even better - such as {{ value[num] }}

Liquid: Can I get a random element from an Array?

I'm trying to pick a random element from an array -- is this possible using Liquid/Jekyll?
I can create an array -- and access a given index ... but is there a way to "shuffle" the array and then select an index, and thus get a random element from the array?
prefix: ["Foo", "Bar", "Baz"]
---
{{ page.prefix[1] }}
# outputs "Bar"
The 2018 answer is
{% assign prefix = page.prefix | sample: 2 %}
{{ prefix[0] }}
As the OP asked about Jekyll, this can be found at: https://jekyllrb.com/docs/templates/
Liquid doesn't have a filter for picking a random element from an array or an integer interval.
If you want Jekyll to do that, you would have to create an extension to add that liquid filter.
However, I must point out that doing so would pick a random element every time the page is generated, but not every time the page is viewed.
If you want to get different random values every time you visit a page, your best option is using javascript and letting the client pick a random value. You can use liquid to generate the relevant javascript though.
You may be able to do that just in Liquid, but it could less of generic solution like the one provided by #Brendan. According to this article, you can generate a random liquid number between min & max. So simply:
Assign the min to 0 and max to your array's length.
Loop over the array till you find your random number and pick you element.
Here is an example, get your random array index:
{% assign min = 0 %}
{% assign max = prefix.size %}
{% assign diff = max | minus: min %}
{% assign randomNumber = "now" | date: "%N" | modulo: diff | plus: min %}
Then find your random value:
{{ prefix[randomNumber] }}
You can create a plugin to get a random element. Something like this:
module Jekyll
module RandomFilter
# Use sample to get a random value from an array
#
# input - The Array to sample.
#
# Examples
#
# random([1, 2, 3, 4, 5])
# # => ([2])
#
# Returns a randomly-selected item out of an array.
def random(input)
input.sample(1)
end
end
end
Liquid::Template.register_filter(Jekyll::RandomFilter)
Then do something like this in your template to implement:
{% assign myArray = '1|2|3|4|5 | split: '|' %}
{% assign myNumber = myArray | random %}
Without using a plugin (which might be a requirement if you are using github pages for example) and don't want the choice to be set only at build/rebuild time.
This uses collections as it's data source and some feature flags set in the page front matter.
{% if page.announcements %}
<script>
// homepage callout
var taglines=[
{% for txt in site.announcements %}
{{ txt.content | markdownify | jsonify | append: "," }}
{% endfor %}
]
var selection = document.querySelector('#tagline') !== null;
if(selection) {
document.querySelector('#tagline').innerHTML = taglines[ Math.floor(Math.random()*taglines.length) ];
}
</script>
{% endif %}
I use markdownify to process the content, jsonify to make it JavaScript safe and then append a comma to make my array.
The Javascript then populates one randomly at page load.
Add collection to config.yml
collections:
announcements:
Add flag to page
---
layout: home
title:
slider: true
announcements: true
---
collection content item (test.md)
---
published: true
---
This is a test post
You could adapt Liquid::Drop and whitelist Ruby's sample method.
See https://github.com/Shopify/liquid/blob/master/lib/liquid/drop.rb#L69:
You would need to change:
blacklist -= [:sort, :count, :first, :min, :max, :include?]
to:
blacklist -= [:sort, :count, :first, :min, :max, :include?, :sample]
Next you could just use:
{{ some_liquid_array.sample }}