JSON path filter for arrays - json

I'm learning JSON paths and I'm struggling with one issue. Unfortunatelly I cannot show the original file I'm working with but I recreated the issue with this simple JSON:
{
"store":{
"book":[
{
"category":"reference",
"author":"Nigel Rees",
"title":"Sayings of the Century",
"price":[
{
"originalEnglish": 8.95,
"currentEnglish":11
},
{
"originalSpanish":11,
"currentSpanish":13
}
]
}
]
}
}
In the original one there's more objects and arrays but basically what I'm trying to do is filter all books with category 'reference' and with originalEnglish price below 10.
I used:
$..book[?(#.price.originalEnglish < 10 && #.category == 'reference')]
but it doesn't work. If anyone could help me out with this, I'd really appreciate it.

This works for me on http://jsonpath.herokuapp.com/
$..book[?(#.price[?(#.originalEnglish < 10)] && #.category == 'reference')]

Related

Read Json dymaic elements values in unix

Need help to read a Json dynamic json data unix
{
"Dept1":{
"Emp1":{
"Name":"D1E1xyz"
"Salary":"1234"
},
"Emp2":{
"Name":"D1E2ABCD"
"Salary":"9867"
}
}
}
{
"Dept2":{
"Emp1":{
"Name":"D2E1xyz"
"Salary":"1234"
},
"Emp2":{
"Name":"D2E2ABCD"
"Salary":"9867"
},
"Emp3":{
"Name":"D2E3PQRS"
"Salary":"9867"
},
}
I'm trying to print using unix commands , have tried couple but stil no luck .. did anyone come across similar case , Please help with code sniper
dept1,1234,9867
dept2,1234,9867,9867

Using JQ to inject element at specific position based on conditions

Pulling my hair here, trying to use jq to parse and extend a JSON file and adding an element at a specific position based on a certain condition.
Here is a sample file (also at https://jqplay.org/s/6cjmbnvrqu)
{
"TopA": { "stuff": "here"},
"TopB": {
"C591AB7E": {
"Type": "this",
"Properties": {
"lots": 1,
"of": 2,
"values" : 3
}
},
"7E16765A": {
"Type": "this",
"Properties": {
"lots": 4,
"of": 5,
"values" : 6
}
},
"AAD76465": {
"Type": "that",
"Properties": {
"lots": 7,
"of": 8,
"values" : 9
}
}
}
}
The goal is to add an element to the Properties node of any TopB child where .Type == "that". And the kicker is that I need to put the child node's key into the new element value with an added prefix.
So essentially I need the last element to look like this:
"AAD76465": {
"Type": "that",
"Properties": {
"lots": 7,
"of": 8,
"values": 9,
"newElement": "Prefix-AAD76465"
}
}
I also need to retain the whole rest of the file (or a new file for that matter). So I don't need a query but really a jq call to manipulate the existing file. Parallel to TopB there could be other elements that I'd still need in the file. And no, I don't know, neither do I have control over the naming of the children of TopB. All I have is that my targets are nested children of TopB with .Type == "that". There can be multiple of those.
Thanks for looking.
If you get the path to where you will be adding the new field first, you can simply extract the parent key from that.
reduce path(.TopB[] | select(.Type == "that") .Properties.newElement) as $p (.; setpath($p; "Prefix-\($p[1])"))
Online demo
Here'a solution that uses walk/1 and is therefore perhaps quite intuitive:
walk(if (type == "object") and .TopB
then .TopB |= with_entries(
.key as $key
| if .value.Type == "that"
then .value.Properties += { newElement: ("Prefix-" + $key) }
else . end)
else . end)
One advantage of this solution is that it meets the stated requirement:
The goal is to add an element to the Properties node of any TopB child ...
in the sense that no assumptions are made about the locations of objects with the "topB" key.

JSONPath issu returning value using a filter

I have the following json, for which I'm having trouble selecting one of the values using a filter. Specifically, I want to return "POS_Undeclared"
{"wd:Program_of_Study_Reference": {
"wd:ID": [
{
"#wd:type": "WID",
"$": "123456789abcde"
},
{
"#wd:type": "Program_of_Study_ID",
"$": "POS_Undeclared"
}
]
}
}
This jsonpath $.wd:Program_of_Study_Reference.wd:ID[1].$ gives me what I need, but I cannot count on the ordering to be consistent or even exist, hence cannot use [1] .
I cannot seem to get a filter like #wd:type == Program_of_Study_ID to work. I'm guessing it is the # and/or the : goofing up my syntax.
How can I filter to get the value POS_Undeclared ?
Try using
$.wd:Program_of_Study_Reference.*[?(#['#wd:type'] == "Program_of_Study_ID")].$

Convert array of hash by logstash to simple hash

I am trying to parse by logstash this:
"attributes": [
{
"value": "ValueA",
"name": "NameA"
},
{
"value": "ValueB",
"name": "NameB"
},
{
"value": "ValueC",
"name": "NameC"
}
],
To this:
"attributes": {
"NameA": "ValueA",
"NameB": "ValueB",
"NameC": "ValueC"
}
Any recommendations?
I don't want to split this list to more records...
I have found th solution. For anyone dealing with a similar problem, here is the solution and a short story...
In the beginning, I tried this:
ruby {
code => '
xx = event.get("[path][to][data_source]")
event.set(['_my_destination'], Hash[xx.collect { |p| [p[:name], p[:value]] }])
'
But it returned an error because of the set method allowing a string only.
So I tried to do it this way:
ruby {
code => '
event.get("[path][to][data_source]").each do |item|
k = item[:name]
event.set("[_my_destination][#{k}]", item[:value])
end
'
}
I spent a lot of time debugging it because it works everywhere except in logstash :-D. After some grumbling, I finally fixed it. The solution with commentary is as follows.
ruby {
code => '
i = 0 # need index to address hash in array
event.get("[json_msg][mail][headers]").each do |item|
# need to use event.get function to get value
k = event.get("[json_msg][mail][headers][#{i}][name]")
v = event.get("[json_msg][mail][headers][#{i}][value]")
# now it is simple
event.set("[json_msg][headers][#{k}]", v)
i += 1
end
'
}
I think you should be able to do it with a custom Ruby script - see the ruby filter. You'll use the Event API to manipulate the event.
Maybe the aggregate filter could be also used but the Ruby script with one for loop seems more straightforward to me.

Iterating over a list in JSON using TypeScript

I'm having a problem iterating over my json in TypeScript. I'm having trouble with one specific json field, the tribe. For some reason I can't iterate over that one. In the debugger, I'm expecting the Orc to show up but instead I get a 0. Why is this? How do I iterate correctly over my tribe data?
// Maps a profession or tribe group name to a bucket of characters
let professionMap = new Map<string, Character[]>()
let tribeMap = new Map<string, Character[]>()
let herolistJson = require('./data/HeroList.json')
for (let hero of herolistJson){
// Certain characters can have more than one tribe
// !!!!! The trouble begins here, tribe is 0???
for (let tribe in hero.tribe){
let tribeBucket = tribeMap.get(tribe) as Character[]
// If the hero does not already exist in this tribe bucket, add it
if(tribeBucket.find(x => x.name == hero.name) === undefined )
{
tribeBucket.push(new Character(hero.name, hero.tribe, hero.profession, hero.cost))
}
}
}
My json file looks like this
[
{
"name": "Axe",
"tribe": ["Orc"],
"profession": "Warrior",
"cost": 1
},
{
"name": "Enchantress",
"tribe": ["Beast"],
"profession": "Druid",
"cost": 1
}
]
in iterates over the keys of an object, not the values. The keys of an array are its indices. If you use of instead, you'll use the newer iterator protocol and an Array's iterator provides values instead of keys.
for (let tribe of /* in */ hero.tribe) {
Note, that this won't work in IE 11, but will work in most other browsers as well many JS environments that are ES2015 compatible. kangax/compat has a partial list.
Change the "in" to "of" in second loop.