Manipulate json, remove two items in a group by key value - json

How can I manipulate this chunk of json:
{
"id": "whatever",
"attributes": [
{
"key": "this",
"value": "A"
},
{
"key": "that",
"value": "B"
},
{
"key": "other",
"value": "C"
}
]
}
So that it matches on "that" and removes the key and value both in that grouping, leaving json like this:
{
"id": "whatever",
"attributes": [
{
"key": "this",
"value": "A"
},
{
"key": "other",
"value": "C"
}
]
}
I am attempting to use jq on linux.

Try this
.attributes |= map(select(.key != "that"))
Demo

Figured it out.
jq 'del(.attributes[] | select(.key == "that"))' test.json | sponge test.json

Related

How to filter an list by the value of an inner dict with jq?

Giving the input JSON:
[
{
"name": "foo",
"value": 1
},
{
"name": "bar",
"value": 1
},
{
"name": "foo",
"value": 2
}
]
I'm trying to get the dicts with the name foo, so the expecting output is:
{
"name": "foo",
"value": 1
},
{
"name": "foo",
"value": 2
}
Try this
jq '.[] | select(.name == "foo")'
Demo

jq sort using the value of a nested array element

I need some help using jq to sort an array of elements where each element contains a nested
tags array of elements. My input JSON looks like this:
{
"result": [
{
"name": "ct-1",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "bb"
}
]
},
{
"name": "ct-2",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "aa"
}
]
}
]
}
I would like to sort using the value of the sequence tag in the nested tags array so that the output looks like this:
{
"result": [
{
"name": "ct-2",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "aa"
}
]
},
{
"name": "ct-1",
"tags": [
{
"key": "service_name",
"value": "BaseCT"
},
{
"key": "sequence",
"value": "bb"
}
]
}
]
}
I have tried the following jq command:
$ jq '.result |= ([.[] | .tags[] | select(.key == "sequence") | .value] | sort_by(.))' input.json
but I get the following result:
{
"result": [
"aa",
"bb"
]
}
Please let me know if you know how to deal with this scenario.
from_entries converts an array of key-value pairs to an object, you can use it with sort_by like this:
.result |= sort_by(.tags | from_entries | .sequence)

Using jq to convert object to key with values

I have been playing around with jq to format a json file but I am having some issues trying to solve a particular transformation. Given a test.json file in this format:
[
{
"name": "A", // This would be the first key
"number": 1,
"type": "apple",
"city": "NYC" // This would be the second key
},
{
"name": "A",
"number": "5",
"type": "apple",
"city": "LA"
},
{
"name": "A",
"number": 2,
"type": "apple",
"city": "NYC"
},
{
"name": "B",
"number": 3,
"type": "apple",
"city": "NYC"
}
]
I was wondering, how can I format it this way using jq?
[
{
"key": "A",
"values": [
{
"key": "NYC",
"values": [
{
"number": 1,
"type": "a"
},
{
"number": 2,
"type": "b"
}
]
},
{
"key": "LA",
"values": [
{
"number": 5,
"type": "b"
}
]
}
]
},
{
"key": "B",
"values": [
{
"key": "NYC",
"values": [
{
"number": 3,
"type": "apple"
}
]
}
]
}
]
I have followed this thread Using jq, convert array of name/value pairs to object with named keys and tried to group the json using this expression
jq '. | group_by(.name) | group_by(.city) ' ./test.json
but I have not been able to add the keys in the output.
You'll want to group the items at the different levels and building out your result objects as you want.
group_by(.name) | map({
key: .[0].name,
values: (group_by(.city) | map({
key: .[0].city,
values: map({number,type})
}))
})
Just keep in mind that group_by/1 yields groups in a sorted order. You'll probably want an implementation that preserves that order.
def group_by_unsorted(key_selector):
reduce .[] as $i ({};
.["\($i|key_selector)"] += [$i]
)|[.[]];

JQ delete property based other property value

I'm trying to write a JQ filter allowing me to selectively filter object properties based on other of it's values.
For example, given following input
{
"object1": {
"Type": "Type1",
"Properties": {
"Property1": "blablabla",
"Property2": [
{
"Key": "Name",
"Value": "xxx"
},
{
"Key": "Surname",
"Value": "yyy"
}
],
"Property3": "xxx"
}
},
"object2": {
"Type": "Type2",
"Properties": {
"Property1": "blablabla",
"Property2": [
{
"Key": "Name",
"Value": "xxx"
},
{
"Key": "Surname",
"Value": "yyy"
}
],
"Property3": "xxx"
}
}
}
I would like to construct a filter, that based upon the object type, say "Type2", deletes or clears a property of that object, say Property2.
The resulting output would then be:
{
"object1": {
"Type": "Type1",
"Properties": {
"Property1": "blablabla",
"Property2": [
{
"Key": "Name",
"Value": "xxx"
},
{
"Key": "Surname",
"Value": "yyy"
}
],
"Property3": "xxx"
}
},
"object2": {
"Type": "Type2",
"Properties": {
"Property1": "blablabla",
"Property3": "xxx"
}
}
}
Any help greatly appreciated. Thanks in advance.
Pretty simple. Find the objects that you want to update, then update them.
Look through the values of your root object, filtering them based on your condition, the update the Properties property deleting the property you want.
(.[] | select(.Type == "Type2")).Properties |= del(.Property2)
Using .[] on an object yields all property values of an object. Also worth mentioning, when you update a value using assignments, the result of the expression just returns the input (in other words, it doesn't change the context).
A direct approach:
.[] |= (if .Type == "Type2" then delpaths([["Properties", "Property2"]]) else . end)

jq group by property in array

I have an input json document as so:
[
{
"Name": "one",
"Tags": [
{
"Key": "Name",
"Value": "important"
},
{
"Key": "OtherTag",
"Value": "irrelevant"
}
]
},
{
"Name": "two",
"Tags": [
{
"Key": "OtherTag",
"Value": "irrelevant2"
},
{
"Key": "Name",
"Value": "important"
}
]
},
{
"Name": "three",
"Tags": [
{
"Key": "Name",
"Value": "important2"
},
{
"Key": "OtherTag",
"Value": "irrelevant3"
}
]
}
]
I want to use jq to group the three records by tag Value where the Key = "Name". The result would be two arrays, one with two records in it and one with one. The array with two records would have two because both records share the same tag with a value of "important". Here is what the result would look like:
[
[
{
"Name": "one",
"Tags": [
{
"Key": "Name",
"Value": "important"
},
{
"Key": "OtherTag",
"Value": "irrelevant"
}
]
},
{
"Name": "two",
"Tags": [
{
"Key": "OtherTag",
"Value": "irrelevant2"
},
{
"Key": "Name",
"Value": "important"
}
]
},
],
[
{
"Name": "three",
"Tags": [
{
"Key": "Name",
"Value": "important2"
},
{
"Key": "OtherTag",
"Value": "irrelevant3"
}
]
}
]
]
I just can't figure out how to do this with jq. Does anyone have any ideas?
Your proposed solution is fine, but if you don't mind converting the arrays of Key-Value pairs into objects, then the following can be used:
map( .Tags |= from_entries ) | group_by(.Tags.Name)
This at least makes the "group_by" easy to understand; furthermore, it would be easy to convert the .Tags objects back to key-value pairs (with lower-case "key" and "value"):
map( .Tags |= from_entries ) | group_by(.Tags.Name)
| map(map( .Tags |= to_entries))
Key/Value capitalization
One way to recover the capitalized Key/Value tags would be to tweak the above as follows:
def KV: map( {Key: .key, Value: .value} );
map( .Tags |= from_entries ) | group_by(.Tags.Name)
| map(map( .Tags |= (to_entries | KV)))