How do I query a complex JSON in Jinja2? - json

I'm parsing a complex JSON with a Jinja2 template in Ansible. The JSON has a lot of items and random arrays.
For example, how could I query the value of name & id if the date < 2001 for all motors? (this should return: Premium diesel & 4). Please note that this is an example structure and it could have random and more children in my real scenario. What I need is a query to r search for the above keys in the entire tree.
{
"cars":[
{
"Ford":[
{
"vehicle":{
"motor":[
{
"diesel":[
{
"regular":{
"name":"Regular diesel",
"specs":{
"law":[
{
"id":1,
"date":"2008"
}
],
"gas_station":[
{
"id":2,
"date":"2002"
}
]
}
},
"premium":{
"name":"Premium diesel",
"specs":{
"law":[
{
"id":3,
"date":"2005"
}
],
"gas_station":[
{
"id":4,
"date":"2000"
}
]
}
}
}
]
}
]
}
}
]
}
]
}

Q: "How could I query the value of name & id if the date < 2001?
(this should return: Premium diesel & 4)
A: Create a list of the items where the date is less than '2001'
year: 2001
vehicle_motors_year:
2001:
- brand: Ford
id: 4
name: Premium diesel
type: gas_station
- brand: Ford
id: 6
name: Natural gasoline
type: gas_station
- brand: VW
id: 12
name: Hybrid hydrogen
type: gas_station
Then select and format the items
result: "{{ vehicle_motors_year[year]|
json_query('[].[name, id]')|
map('join', ' & ') }}"
gives the expected result
result:
- Premium diesel & 4
- Natural gasoline & 6
- Hybrid hydrogen & 12
Details:
Given the list of cars for testing
cars:
- Ford:
- vehicle:
motor:
- diesel:
- premium:
name: Premium diesel
specs:
gas_station:
- date: '2000'
id: 4
law:
- date: '2005'
id: 3
regular:
name: Regular diesel
specs:
gas_station:
- date: '2002'
id: 2
law:
- date: '2008'
id: 1
- gasoline:
- natural:
name: Natural gasoline
specs:
gas_station:
- date: '2000'
id: 6
law:
- date: '2005'
id: 5
- VW:
- vehicle:
motor:
- hybrid:
- hydrogen:
name: Hybrid hydrogen
specs:
gas_station:
- date: '2000'
id: 12
law:
- date: '2005'
id: 11
Get the lists of brands and motors
brands: "{{ cars|map('first') }}"
motors: "{{ cars|json_query(query_motors) }}"
query_motors: '[].*[][].vehicle[].motor'
give
brands:
- Ford
- VW
motors:
- - diesel:
- premium:
name: Premium diesel
specs:
gas_station:
- date: '2000'
id: 4
law:
- date: '2005'
id: 3
regular:
name: Regular diesel
specs:
gas_station:
- date: '2002'
id: 2
law:
- date: '2008'
id: 1
- gasoline:
- natural:
name: Natural gasoline
specs:
gas_station:
- date: '2000'
id: 6
law:
- date: '2005'
id: 5
- - hybrid:
- hydrogen:
name: Hybrid hydrogen
specs:
gas_station:
- date: '2000'
id: 12
law:
- date: '2005'
id: 11
Create a dictionary of the brands' vehicles' motors
vehicle_motors_str: |
{% for motor in motors %}
{{ brands[loop.index0] }}:
{% for fuels in motor %}
{% for fuel,types in fuels.items() %}
{% for type in types %}
{% for k,v in type.items() %}
{{ fuel }}_{{ k }}:
{{ v }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
vehicle_motors: "{{ vehicle_motors_str|from_yaml }}"
gives
vehicle_motors:
Ford:
diesel_premium:
name: Premium diesel
specs:
gas_station:
- date: '2000'
id: 4
law:
- date: '2005'
id: 3
diesel_regular:
name: Regular diesel
specs:
gas_station:
- date: '2002'
id: 2
law:
- date: '2008'
id: 1
gasoline_natural:
name: Natural gasoline
specs:
gas_station:
- date: '2000'
id: 6
law:
- date: '2005'
id: 5
VW:
hybrid_hydrogen:
name: Hybrid hydrogen
specs:
gas_station:
- date: '2000'
id: 12
law:
- date: '2005'
id: 11
Use this dictionary to find items where the date is less than '2001'
year: 2001
vehicle_motors_year_str: |
{{ year }}:
{% for brand,fuels in vehicle_motors.items() %}
{% for fuel,types in fuels.items() %}
{% for k,v in types.specs.items() %}
{% for i in v %}
{% if i.date|int < year|int %}
- name: {{ types.name }}
id: {{ i.id }}
brand: {{ brand }}
type: {{ k }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
vehicle_motors_year: "{{ vehicle_motors_year_str|from_yaml }}"
gives
vehicle_motors_year:
2001:
- brand: Ford
id: 4
name: Premium diesel
type: gas_station
- brand: Ford
id: 6
name: Natural gasoline
type: gas_station
- brand: VW
id: 12
name: Hybrid hydrogen
type: gas_station
Example of a complete playbook for testing
- hosts: localhost
vars:
cars:
- Ford:
- vehicle:
motor:
- diesel:
- premium:
name: Premium diesel
specs:
gas_station:
- date: '2000'
id: 4
law:
- date: '2005'
id: 3
regular:
name: Regular diesel
specs:
gas_station:
- date: '2002'
id: 2
law:
- date: '2008'
id: 1
- gasoline:
- natural:
name: Natural gasoline
specs:
gas_station:
- date: '2000'
id: 6
law:
- date: '2005'
id: 5
- VW:
- vehicle:
motor:
- hybrid:
- hydrogen:
name: Hybrid hydrogen
specs:
gas_station:
- date: '2000'
id: 12
law:
- date: '2005'
id: 11
brands: "{{ cars|map('first') }}"
motors: "{{ cars|json_query(query_motors) }}"
query_motors: '[].*[][].vehicle[].motor'
vehicle_motors_str: |
{% for motor in motors %}
{{ brands[loop.index0] }}:
{% for fuels in motor %}
{% for fuel,types in fuels.items() %}
{% for type in types %}
{% for k,v in type.items() %}
{{ fuel }}_{{ k }}:
{{ v }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
vehicle_motors: "{{ vehicle_motors_str|from_yaml }}"
year: 2001
vehicle_motors_year_str: |
{{ year }}:
{% for brand,fuels in vehicle_motors.items() %}
{% for fuel,types in fuels.items() %}
{% for k,v in types.specs.items() %}
{% for i in v %}
{% if i.date|int < year|int %}
- name: {{ types.name }}
id: {{ i.id }}
brand: {{ brand }}
type: {{ k }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
vehicle_motors_year: "{{ vehicle_motors_year_str|from_yaml }}"
tasks:
- debug:
var: brands
- debug:
var: motors
- debug:
var: vehicle_motors
- debug:
var: vehicle_motors_year
If you get rid of the redundant lists
cars:
Ford:
vehicle:
motor:
diesel:
premium:
name: Premium diesel
specs:
gas_station:
- {date: 2000, id: 4}
law:
- {date: 2005, id: 3}
regular:
name: Regular diesel
specs:
gas_station:
- {date: 2002, id: 2}
law:
- {date: 2008, id: 1}
gasoline:
natural:
name: Natural gasoline
specs:
gas_station:
- {date: 2000, id: 6}
law:
- {date: 2005, id: 5}
VW:
vehicle:
motor:
hybrid:
hydrogen:
name: Hybrid hydrogen
specs:
gas_station:
- {date: 2000, id: 12}
law:
- {date: 2005, id: 11}
Create the dictionary brands_motors
brands_motors: "{{ dict(cars.keys()|list|
zip(cars|
json_query('*.*.*.*.*')|
flatten(levels=2)|
map('flatten'))) }}"
gives
brands_motors:
Ford:
- name: Premium diesel
specs:
gas_station:
- date: 2000
id: 4
law:
- date: 2005
id: 3
- name: Regular diesel
specs:
gas_station:
- date: 2002
id: 2
law:
- date: 2008
id: 1
- name: Natural gasoline
specs:
gas_station:
- date: 2000
id: 6
law:
- date: 2005
id: 5
VW:
- name: Hybrid hydrogen
specs:
gas_station:
- date: 2000
id: 12
law:
- date: 2005
id: 11
Create a list of the motors
motors_str: |
{% for brand,motors in brands_motors.items() %}
{% for motor in motors %}
{% for spec,types in motor.specs.items() %}
{% for type in types %}
- brand: {{ brand }}
name: {{ motor.name }}
spec: {{ spec }}
date: {{ type.date }}
id: {{ type.id }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
motors: "{{ motors_str|from_yaml }}"
gives
motors:
- {brand: Ford, date: 2000, id: 4, name: Premium diesel, spec: gas_station}
- {brand: Ford, date: 2005, id: 3, name: Premium diesel, spec: law}
- {brand: Ford, date: 2002, id: 2, name: Regular diesel, spec: gas_station}
- {brand: Ford, date: 2008, id: 1, name: Regular diesel, spec: law}
- {brand: Ford, date: 2000, id: 6, name: Natural gasoline, spec: gas_station}
- {brand: Ford, date: 2005, id: 5, name: Natural gasoline, spec: law}
- {brand: VW, date: 2000, id: 12, name: Hybrid hydrogen, spec: gas_station}
- {brand: VW, date: 2005, id: 11, name: Hybrid hydrogen, spec: law}
The selection is trivial
year: 2001
result: "{{ motors|
selectattr('date', 'lt', year)|
json_query('[].[name, id]')|
map('join', ' & ') }}"
gives the expected result
result:
- Premium diesel & 4
- Natural gasoline & 6
- Hybrid hydrogen & 12

Related

Ansible converting month to integer

I haven't found anything for this yet.
I am using Ansible and I'm trying to change some values after a decent amount of time.
But my problem is I get a value like:
2020 Nov 19
But I need it to be like:
2020 11 19
How can I do this?
using to_datetime and strftime you can achieve it. the filters to apply would be:
"{{ '%Y %m %d' | strftime(( my_date_string | to_datetime('%Y %b %d')).strftime('%s')) }}"
as reference, please see the examples here. The idea is to convert your string value to datetime using the to_datetime, then to epoch time using strftime, and finally reformat that to your desired YYYY MM DD.
A PB with 3 example dates:
---
- hosts: localhost
gather_facts: false
vars:
my_date_examples:
- "2020 Nov 04"
- "2020 Apr 11"
- "2020 Aug 23"
tasks:
- name: reformat date string
debug:
msg: "{{ '%Y %m %d' | strftime(( item | to_datetime('%Y %b %d')).strftime('%s')) }}"
loop: "{{ my_date_examples }}"
output:
TASK [reformat date string] *******************************************************************************************************************************************************************************************
ok: [localhost] => (item=2020 Nov 04) => {
"msg": "2020 11 04"
}
ok: [localhost] => (item=2020 Apr 11) => {
"msg": "2020 04 11"
}
ok: [localhost] => (item=2020 Aug 23) => {
"msg": "2020 08 23"
}
cheers

Sort Products by Published date in collection page - SHOPIFY

We want our products sorted out by Publish Date, (not by created date)
I'm sure this is possible in Shopify, I just don't get what I'm missing.
{% assign date_now_sort = 'now' | date:'%s' %}
{% assign product_sort = collection.products | sort: 'published_at' | reverse %}
{% for product in product_sort %}
{% assign date_published = product.published_at | date:'%s' %}
{% assign date_now = 'now' | date:'%s' %}
{% assign date_difference = date_now | minus: date_published %}
{% if date_difference < 5259492 %}
<div id="product-loop">
{% for product in collection.products %}
{% assign products-per-row = section.settings.products-per-row %}
<div id="product-listing-{{ product.id }}" class="product-index {% if products-per-row == 6 or products-per-row == "6" %}desktop-2{% cycle ' first', '', '', '', '', ' last' %}{% elsif products-per-row == 4 or products-per-row == "4" %}desktop-3{% cycle ' first', '', '', ' last' %}{% elsif products-per-row == 3 or products-per-row == "3" %}desktop-4{% cycle ' first', '', ' last' %}{% elsif products-per-row == 5 or products-per-row == "5" %}desktop-fifth{% cycle ' first', '', '', '', ' last' %}{% elsif products-per-row == 2 or products-per-row == "2" %}desktop-6{% cycle ' first', ' last' %}{% endif %} tablet-half mobile-half" data-alpha="{{ product.title }}" data-price="{{ product.price }}">
{% include 'product-listing' %}
</div>
{% endfor %}
</div>
{% endif %}
{% endfor %}
This is what I came up with.
{%- assign dates = '' -%}
{%- assign datesHandles = '' -%}
{%- for product in collections.all.products limit: 20 -%}
{%- assign createdAt = product.created_at | date: '%s' -%}
{%- assign dates = dates | append: createdAt | append: ',' -%}
{%- assign datesHandles = datesHandles | append: product.handle | append: '#' | append: createdAt | append: ',' -%}
{%- endfor -%}
{%- assign dates = dates | split: ',' | sort | reverse -%}
{%- assign datesHandles = datesHandles | split: ',' -%}
{%- for orderedDate in dates -%}
{%- for dateHandle in datesHandles -%}
{%- assign dateHandleArr = dateHandle | split: '#' -%}
{%- if orderedDate == dateHandleArr[1] -%}
{{ all_products[dateHandleArr[0]].title }}<br/>
{% break %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
The issue is that you are limited by all_products which allows only 20 unique handle request.
So this code will show only the first 20 products ordered by created date, which I don't know if it will be of any use to you.

Convert numerical month to string using ionic 2 Pipe

How can I convert month to string in ionic 2 using Pipe? given the sample data below:
In my .ts file
let users = [
{
user: "A",
birthDate: "2017-08-01"
},
{
user: "B",
birthDate: "2017-08-02"
},
{
user: "C",
birthDate: "2017-08-03"
},
{
user: "D",
birthDate: "2017-08-04"
}
]
In my .html file
<ion-list>
<ion-item *ngFor="let user of users">
<div>Name: {{user.name}}</div>
<div>Birth Date: {{user.birthDate | date: "MM dd, yyyy"}}</div>
</ion-item>
</ion-list>
The sample output will be
Name: A
Birth Date: 08 01, 2017
Name: B
Birth Date: 08 02, 2017
Name: C
Birth Date: 08 03, 2017
Name: D
Birth Date: 08 04, 2017
Expected output will be
Name: A
Birth Date: August 01, 2017
Name: B
Birth Date: August 02, 2017
Name: C
Birth Date: August 03, 2017
Name: D
Birth Date: August 04, 2017
How can I achieve expected output?
Use MMMM instead of MM
<ion-list>
<ion-item *ngFor="let user of users">
<div>Name: {{user.name}}</div>
<div>Birth Date: {{user.birthDate | date: "MMMM dd, yyyy"}}</div>
</ion-item>
</ion-list>

List categories associated with post in Jekyll

I'm using Jekyll as my blogging platform and it's great. Right now I have the following code that I'm trying to tweak in my index.html page so that it only displays the categories associated with each post.
For example let's say I have the following posts:
| Post Name | Category |
|--------------|---------------|
| Post1 | Travel Dining |
| Post2 | Projects |
When the post list displays I want to get something like:
Post1, 6/7/15, Category: Travel Dining
Here's what I have for code:
Filed In:
{% for category in site.categories %}
{{ category | first }}
{% endfor %}
You question is not clear but maybe this code can do the job.
<ul>
{% for p in site.posts %}
<li>
{{p.title}} -
{{ p.date | date: "%a, %b %d, %y" }}
{% unless p.categories == empty %}
-
{% for cat in p.categories %}
<h1>{{ cat }}</h1>
{% endfor %}
{% endunless %}
</li>
{% endfor %}
</ul>

Searching through databases serialized column

In MySQL Rails 3 application, one of my columns are serialized to Hash. My question is simple: how can I get results based on this column?
I tried this approach:
example_hash = {id: 666}
ExampleTable.last.hash == example_hash
:true ###### Here you can see that both hashes are the same
Still, a query like this give me no results and no exceptions:
ExampleTable.where('hash LIKE ?', example_hash)
It just doesn't detect the record I need.
my_hash = {id:666}
search_term = my_hash.serializable_hash
ExampleTable.where(search_term)
I tried this in an existing Rails 4 app. You will have to test if it works in Rails 3. I don't have include ActiveModel::Serialization in my model and it still works.
Here is my console session:
Loading development environment (Rails 4.0.0)
$pry(main)> t = Tool.first
Tool Load (10.9ms) SELECT "tools".* FROM "tools" ORDER BY "tools"."id" ASC LIMIT 1
=> #<Tool id: 2, name: "6", serial: "134989652", purchased: nil, put_in_service: nil, cost: nil, value: nil, in_service: true, retired: nil, created_at: "2013-07-17 06:12:59", updated_at: "2014-02-13 17:19:10", note: "", condition: "5 - Brand New Condition", old_location: "Sta 75", model: "Stihl 066", loaner: false, location_id: 9, category_id: 2, annual_service: false>
$pry(main)> x = t.serializable_hash
=> {"id"=>2,
"name"=>"6",
"serial"=>"134989652",
"purchased"=>nil,
"put_in_service"=>nil,
"cost"=>nil,
"value"=>nil,
"in_service"=>true,
"retired"=>nil,
"created_at"=>Tue, 16 Jul 2013 23:12:59 PDT -07:00,
"updated_at"=>Thu, 13 Feb 2014 09:19:10 PST -08:00,
"note"=>"",
"condition"=>"5 - Brand New Condition",
"old_location"=>"Sta 75",
"model"=>"Stihl 066",
"loaner"=>false,
"location_id"=>9,
"category_id"=>2,
"annual_service"=>false}
$pry(main)> Tool.where(x)
Tool Load (10.3ms) SELECT "tools".* FROM "tools" WHERE "tools"."id" = 2 AND "tools"."name" = '6' AND "tools"."serial" = '134989652' AND "tools"."purchased" IS NULL AND "tools"."put_in_service" IS NULL AND "tools"."cost" IS NULL AND "tools"."value" IS NULL AND "tools"."in_service" = 't' AND "tools"."retired" IS NULL AND "tools"."created_at" = '2013-07-17 06:12:59.638381' AND "tools"."updated_at" = '2014-02-13 17:19:10.674233' AND "tools"."note" = '' AND "tools"."condition" = '5 - Brand New Condition' AND "tools"."old_location" = 'Sta 75' AND "tools"."model" = 'Stihl 066' AND "tools"."loaner" = 'f' AND "tools"."location_id" = 9 AND "tools"."category_id" = 2 AND "tools"."annual_service" = 'f'
=> [#<Tool id: 2, name: "6", serial: "134989652", purchased: nil, put_in_service: nil, cost: nil, value: nil, in_service: true, retired: nil, created_at: "2013-07-17 06:12:59", updated_at: "2014-02-13 17:19:10", note: "", condition: "5 - Brand New Condition", old_location: "Sta 75", model: "Stihl 066", loaner: false, location_id: 9, category_id: 2, annual_service: false>]