jq merge array of keys with array of values - json

I have a json fragment with an array of keys and a separate array of values. Key 1 should match up to Value 1, etc. I'm trying to reformat with jq but not having much luck.
Original JSON:
{
"result": {
"event.KeyValues{}.Key": [
"name",
"gender",
"employee",
"email"
],
"event.KeyValues{}.Value": [
"tyler",
"male",
"yes",
"tyler#nowhere.com"
],
"foo": "1",
"bar": "2"
}
}
Desired Output:
{
"name": "tyler",
"gender": "male",
"employee": "yes",
"email": "tyler#nowhere.com"
}

Use transpose to pair keys and values. Then you can make an object out of each pair and add them together to get the desired structure.
.result
| [."event.KeyValues{}.Key", ."event.KeyValues{}.Value"]
| transpose
| map({(.[0]): .[1]})
| add
Online demo

Related

Retrieve value based on contents of another value

I have this json that i am trying to get the just the id out of based on a contains from another value. I am able to jq the contains part but when I add on | .id i cannot get a result
{
"restrictions": [
{
"id": 1,
"database": {
"match": "exact",
"value": "db_contoso"
},
"measurement": {},
"permissions": [
"write"
]
},
{
"id": 2,
"database": {
"match": "exact",
"value": "db2_contoso"
},
"measurement": {},
"permissions": [
"write"
]
}
]
}
When id run
jq -r '.restrictions[] | .database.value | select(contains("conto")?)
I get the values of db_contoso and db2_contoso. but I am trying to pull just the id based on that. When I add | .id to the end of that command I get nothing.
So that would be to do below. Select the whole object matching the condition and get the value of .id
jq '.restrictions[] | select(.database.value | contains("conto")).id'

Using jq find key/value pair based on another key/value pair

I'm pasting here a JSON example data which would require some manipulation to get a desired output which is mentioned in the next section to be read after this piece of JSON code.
I want to use jq for parsing my desired data.
{
"MetricAlarms": [
{
"EvaluationPeriods": 3,
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"AlarmActions": [
"Unimportant:Random:alarm:ELK2[10.1.1.2]-Root-Disk-Alert"
],
"AlarmName": "Unimportant:Random:alarm:ELK1[10.1.1.0]-Root-Alert",
"Dimensions": [
{
"Name": "path",
"Value": "/"
},
{
"Name": "InstanceType",
"Value": "m5.2xlarge"
},
{
"Name": "fstype",
"Value": "ext4"
}
],
"DatapointsToAlarm": 3,
"MetricName": "disk_used_percent"
},
{
"EvaluationPeriods": 3,
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"AlarmActions": [
"Unimportant:Random:alarm:ELK2[10.1.1.2]"
],
"AlarmName": "Unimportant:Random:alarm:ELK2[10.1.1.2]",
"Dimensions": [
{
"Name": "path",
"Value": "/"
},
{
"Name": "InstanceType",
"Value": "r5.2xlarge"
},
{
"Name": "fstype",
"Value": "ext4"
}
],
"DatapointsToAlarm": 3,
"MetricName": "disk_used_percent"
}
]
}
So when I Pass some Key1 & value1 as a parameter "Name": "InstanceType", to the JQ probably using cat | jq and output expected should be as below
m5.2xlarge
r5.2xlarge
A generic approach to search for a key-value pair (sk-sv) in input recursively and extract another key's value (pv) from objects found:
jq -r --arg sk Name \
--arg sv InstanceType \
--arg pv Value \
'.. | objects | select(contains({($sk): $sv})) | .[$pv]' file

jq: extract a specific key from one object to another

I have two JSON files.
file1.json:
{
"Fruits": [
{
"name": "Apple",
"something_else": 123,
"id": 652090
},
{
"name": "Orange",
"something_else": 456,
"id": 28748
}
]}
file2.json:
{
"Fruits": [
{
"weight": 5,
"id": 652090
},
{
"weight": 7,
"id": 28748
}
]}
I want to combine objects from both files if they have a common key 'id', but to extract only 'name' property from file1. How do I do that using jq?
This is what I want to get:
{
"Fruits": [
{
"name": "Apple",
"weight": 5,
"id": 652090
},
{
"name": "Orange",
"weight": 7,
"id": 28748
},
]}
Combine Fruits arrays, group it by id, select groups with 2 elements because we want fruits present in both files. For each selected group; add name field from first group element to second, and collect results in an array.
jq -n '[inputs.Fruits[]]
| reduce (group_by(.id)[] | select(length==2)) as $f
([]; . + [$f[1] + ($f[0] | {name})])' file1.json file2.json
Note that the order files are given on the command line is important, the file with names should be given before the other.
Combining objects with same id and extracting a subset of fields is way much easier though:
jq -n '[inputs.Fruits[]]
| group_by(.id)
| map(select(length==2) | add | {name, id, weight})
' file1.json file2.json
There's plenty of ways this could be constructed. Here's another way:
$ jq '.Fruits |= (. + input.Fruits | [group_by(.id)[] | add | {name,weight,id}])' \
file1.json file2.json
{
"Fruits": [
{
"name": "Orange",
"weight": 7,
"id": 28748
},
{
"name": "Apple",
"weight": 5,
"id": 652090
}
]
}

How can I output a json with the new key name from the value in an existing json by jq

I have an existing json which have a from like this:
{
"arg1": "Admin",
"arg2": 0,
"data": [
{
"arg3": "11",
"user": "user1",
"age": 51,
"arg4": "11"
},
{
"arg3": "22",
"user": "user2",
"age": 52,
"arg4": "22"
},
{
"arg3": "33",
"user": "user3",
"age": 53,
"arg4": "33"
},
{
"arg3": "44",
"user": "user4",
"age": 54,
"arg4": "44"
}
]
}
Then I try this command:
$ cat tmp.json|jq '.data|.[]|{user,age}'
{
"user": "user1",
"age": 51,
}
{
"user": "user2",
"age": 52,
}
{
"user": "user3",
"age": 53,
}
{
"user": "user4",
"age": 54,
}
What I expect to output is:
{
"department": "Admin",
"user_age": {
"user1": "51",
"user2": "52",
"user3": "53",
"user4": "54"
},
"year": 2016
}
In jq's manual, my request is close to example 23.
So I tried to use from_entries function
cat tmp.json|jq '.data|.[]|{user,age}|from_entries'
but get this error:
jq: error (at :30): Cannot index string with string "key"
I know this is because of its format not equal an entry.
So, what should I do to convert to the expected output?
from_entries expects an array of objects with key and value properties. You are however generating separate objects with user and age properties which just would not work. First of all, you would need to make sure that the properties are in an array, then have the separate key/value pairs for each of the values you want in the array.
With that said, you don't really need to use entries to build out the result, it's not the right tool for the job. You just want to pull some properties from each of the data objects and add to another object mapping users to ages. There's many ways this can be achieved, I would use reduce to accomplish this.
reduce .data[] as $d ({}; .[$d.user] = $d.age)
To get your final result, just combine the parts you need into the object you're requiring. I'm not sure where you got that 2016 from, I'm assuming it's just hardcoded.
{department: .arg1, user_age: (reduce .data[] as $d ({}; .[$d.user] = $d.age)), year: 2016}
you can also try:
cat tmp.json|jq '{department: .arg1, user_age: (.data|map({(.user): .age})|add), year: 2016}'
or
cat tmp.json|jq '{department: .arg1, user_age: .data|map({(.user): .age})|add, year: 2016}'
As Jeff explained, from_entries expects input of the form
[ {key:xxx, value:yyy} ]
so Hao's filter
.data | .[] | {user,age} | from_entries
requires two small modifications to generate the desired user_age object:
the values must be {key,value} objects
the values need to be collected into an array
e.g.
.data | [.[]|{key:user, value:age|tostring}] | from_entries
(we include tostring because the values in the example output are strings)
But since [ .[]| ... ] is the same as map(...) this could be written
.data | map({key:user, value:age|tostring}) | from_entries
Here is a complete solution:
{
"department": .arg1,
"user_age": .data | map({key:.user, value:.age|tostring}) | from_entries,
"year": 2016
}
Sample output
{
"department": "Admin",
"user_age": {
"user1": "51",
"user2": "52",
"user3": "53",
"user4": "54"
},
"year": 2016
}

How to filter an array of objects based on value of a element in the Json in JQ

I am trying to get a value from the Json using JQ.
I have to get a ID from the inputJson , (activeItem) and use that ID to get the name of the element from list of items below.
Can this be done in single query ?
{
"amazon": {
"activeitem" : 2,
"items": [
{
"id" : 1,
"name": "harry potter",
"state": "sold"
},
{
"id" : 2,
"name": "adidas shoes",
"state": "in inventory"
},
{
"id" : 3,
"name": "watch",
"state": "returned"
}
]
}
}
Now i am getting the value first and the filtering, instead i want to do in single query.
With your data, the filter:
.amazon
| .activeitem as $id
| .items[]
| select(.id == $id)
| .name
produces:
"adidas shoes"
(Use the -r command-line option if you want the raw string.)