jq select dynamic items from json - json

I have JSON like this:
{
"photo_807": "Ih2RnaBTg2o.jpg",
"photo_604": "zodCm9fQgX8.jpg",
"photo_130": "4Dx-SUNKBw4.jpg",
"photo_75": "7COWb8ou1qA.jpg",
"user_id": 100,
"owner_id": -2435432542783750,
"access_key": "fc5275423676514042234324265cc3df7607c",
"post_id": 380435645368865101,
"date": 14858616848616779856424245814,
"text": "",
"height": 417,
"width": 740,
"id": 45624575446886886564368555,
"album_id": -36
}
I want to get only Photo values, from output i want get this:
"photo_807": "Ih2RnaBTg2o.jpg"
"photo_604": "zodCm9fQgX8.jpg"
"photo_130": "4Dx-SUNKBw4.jpg"
Now about my problem, from next JSON file i will get photo items with new names like this:
"photo_181": "Ih2RnaBTg2o.jpg",
"photo_583": "zodCm9fQgX8.jpg",
"photo_975": "4Dx-SUNKBw4.jpg",
"photo_32": "7COWb8ou1qA.jpg",
How I can get this values from dynamic items photo_* ?
I try something like this:
cat ./json3.txt | jq '.response.items[].attachments[].photo | select(.photo | startswith("photo"))'
But it doesn't work.
When I run :
cat ./json3.txt | jq '.response.items[].attachments[].photo'
I got this output with all items:
{
"photo_807": "Ih2RnaBTg2o.jpg",
"photo_604": "zodCm9fQgX8.jpg",
"photo_130": "4Dx-SUNKBw4.jpg",
"photo_75": "7COWb8ou1qA.jpg",
"user_id": 100,
"owner_id": -2435432542783750,
"access_key": "fc5275423676514042234324265cc3df7607c",
"post_id": 380435645368865101,
"date": 14858616848616779856424245814,
"text": "",
"height": 417,
"width": 740,
"id": 45624575446886886564368555,
"album_id": -36
}
Can someone help me?
Thanks in advance!

You can use a jq filter as below as tested on jq-play!
jq '. | to_entries[] | select(.key | startswith("photo")) | "\(.key) :\(.value)"' json
"photo_807 :Ih2RnaBTg2o.jpg"
"photo_604 :zodCm9fQgX8.jpg"
"photo_130 :4Dx-SUNKBw4.jpg"
"photo_75 :7COWb8ou1qA.jpg"
The idea is to use the to_entries[] built-in, which converts your input into a key-value pair as below. See below the output of just using to_entries[]
jq '. | to_entries[]' json
{
"key": "photo_807",
"value": "Ih2RnaBTg2o.jpg"
}
{
"key": "photo_604",
"value": "zodCm9fQgX8.jpg"
}
{
"key": "photo_130",
"value": "4Dx-SUNKBw4.jpg"
}
{
"key": "photo_75",
"value": "7COWb8ou1qA.jpg"
}
{
"key": "user_id",
"value": 100
}
{
"key": "owner_id",
"value": -2435432542783750
}
{
"key": "access_key",
"value": "fc5275423676514042234324265cc3df7607c"
}
{
"key": "post_id",
"value": 380435645368865100
}
{
"key": "date",
"value": 14858616848616779000000000000
}
{
"key": "text",
"value": ""
}
{
"key": "height",
"value": 417
}
{
"key": "width",
"value": 740
}
{
"key": "id",
"value": 45624575446886885000000000
}
{
"key": "album_id",
"value": -36
}
On this output, we are filtering on the .key value which starts with your string, photo in your case, using the built-in startswith(), and printing the both the .key and .value pair for the matching objects.

Related

Check if Json field Exist, giving default value with (select) jq command

I have some JSON data and i want to push some of them to DB , but sometimes the json values not exists for specific devices:
from all of the following data I want just to pull , "ICCID","MDN","MSISDN","MCC","MNC","FeatureTypes","RatePlanCode","RatePlanDescription","DeviceState","BillingCycleStartDate","BillingCycleEndDate","CurrentBillCycleDataUnRatedUsage"
and if any one not exist print not-exist .
{
"categories": [{
"categoryName": "DeviceIdentifier",
"extendedAttributes": [{
"key": "ICCID",
"value": "89148000"
},
{
"key": "IMSI",
"value": "31148094"
},
{
"key": "MDN",
"value": "5514048068"
},
{
"key": "MEID",
"value": "A0000000005006"
},
{
"key": "MIN",
"value": "5514041185"
}
]
},
{
"categoryName": "DeviceAttributes",
"extendedAttributes": [{
"key": "MCC",
"value": "311"
},
{
"key": "MNC",
"value": "480"
},
{
"key": "FeatureCodes",
"value": "75802,84777,54307"
},
{
"key": "FeatureNames",
"value": "75802,84777,54307"
},
{
"key": "FeatureTypes",
"value": "4G Public Dynamic"
},
{
"key": "RatePlanCode",
"value": "4G5G "
},
{
"key": "RatePlanDescription",
"value": "4G5G"
},
{
"key": "Services",
"value": "null"
}
]
},
{
"categoryName": "Provisioning",
"extendedAttributes": [{
"key": "LastActivationDate",
"value": "2022-03-01T19:38:52Z"
},
{
"key": "CreatedAt",
"value": "2021-12-01T21:22:55Z"
},
{
"key": "DeviceState",
"value": "active"
},
{
"key": "LastDeactivationDate",
"value": "2021-12-01T21:22:55Z"
}
]
},
{
"categoryName": "Connectivity",
"extendedAttributes": [{
"key": "Connected",
"value": "true"
},
{
"key": "LastConnectionDate",
"value": "2022-09-08T03:38:55Z"
},
{
"key": "LastDisconnectDate",
"value": "2022-09-08T03:25:15Z"
}
]
},
{
"categoryName": "Billing",
"extendedAttributes": [{
"key": "BillingCycleStartDate",
"value": "2022-09-02T00:00:00Z"
},
{
"key": "BillingCycleEndDate",
"value": "2022-10-01T00:00:00Z"
},
{
"key": "DefaultRatePlan",
"value": "0"
}
]
},
{
"categoryName": "Usage",
"extendedAttributes": [{
"key": "CurrentRatedUsageRecordDate",
"value": "2022-09-04T00:00:00Z"
}, {
"key": "CurrentUnRatedUsageRecordDate",
"value": "2022-09-08T01:25:15Z"
},
{
"key": "CurrentBillCycleDataUnRatedUsage",
"value": "1698414605"
}
]
}
]
}
i'm not pushing all fields to db so i'm selecting a specific keys from that,
(what i'am selecting its fixed not changed) so the select will not change and always will be :
Expected output :
"89148000"
"5514048068"
"not-exist"
"4G Public Dynamic"
"4G5G"
"4G5G"
"active"
"2022-09-02T00:00:00Z"
"2022-10-01T00:00:00Z"
"2022-09-08T01:25:15Z"
I would like to check if the value of key is missing for this case "MSISDN" ,if not will print for me not-exist or null
any help ?
.categories[].Attributes[] |
if (.key | IN(["AAA","BBB","DDD","EEE"][]))
then .value
else "NOT-EXIST"
end
Gives the following output
"111"
"222"
"NOT-EXIST"
"444"
"555"
First we loop over the Attributes
Then we use an if to;
Check if key exist in ["AAA","BBB","DDD","EEE"]
TRUE: use .value
FALSE: use NOT-EXIST as value
Demo
Another approach, using with_entries() to update the .value before looping over all the objects to show just the value, gives the same output as above:
.categories[].Attributes[]
| select(.key | IN(["AAA","BBB","DDD","EEE"][]) | not).value = "NOT-EXIST"
| .value
Demo
I hope I understood your requirements correctly, but here is a solution that looks simple enough to understand and should be somewhat efficient. If you always expect the same 5 keys in your input, you can try:
.categories[].Attributes | from_entries as $attr
| ["AAA", "BBB", "CCC", "DDD", "EEE"]
| map($attr[.] // "NOT-EXIST")
Input:
{"categories": [
{
"categoryName": "Device",
"Attributes": [
{
"key": "AAA",
"value": "111"
},
{
"key": "BBB",
"value": "222"
},
{
"key": "DDD",
"value": "444"
},
{
"key": "EEE",
"value": "555"
}
]
}]}
Output:
[
"111",
"222",
"NOT-EXIST",
"444",
"555"
]
If you require only the values, add [] or | .[] at the end of the script or rewrite to:
.categories[].Attributes | from_entries as $attr
| "AAA", "BBB", "CCC", "DDD", "EEE"
| $attr[.] // "NOT-EXIST"
With the input from updated question, you intend to first merge all extendedAttributes array into one big array, convert to an object and then use this complete object to look up your values:
.categories | map(.extendedAttributes[]) | from_entries as $attr
| "ICCID", "MDN", "MSISDN", "MCC", "MNC", "FeatureTypes", "RatePlanCode", "RatePlanDescription", "DeviceState", "BillingCycleStartDate", "BillingCycleEndDate", "CurrentBillCycleDataUnRatedUsage"
| $attr[.] // "NOT-EXIST"
.categories | map(.extendedAttributes[]) can be rewritten as [.categories[].extendedAttributes[]] or .categories | map(.extendedAttributes) | add, which might be easier to grok.
Output:
"89148000"
"5514048068"
"NOT-EXIST"
"311"
"480"
"4G Public Dynamic"
"4G5G "
"4G5G"
"active"
"2022-09-02T00:00:00Z"
"2022-10-01T00:00:00Z"
"1698414605"
A version without an intermediate variable is also possible:
[
.categories | map(.extendedAttributes[]) | from_entries[
"ICCID",
"MDN",
"MSISDN",
"MCC",
"MNC",
"FeatureTypes",
"RatePlanCode",
"RatePlanDescription",
"DeviceState",
"BillingCycleStartDate",
"BillingCycleEndDate",
"CurrentBillCycleDataUnRatedUsage"
]
]
| map(. // "NOT-EXIST")
or
[
.categories | map(.extendedAttributes[]) | from_entries
| .["ICCID", "MDN", "MSISDN", "MCC", "MNC", "FeatureTypes", "RatePlanCode", "RatePlanDescription", "DeviceState", "BillingCycleStartDate", "BillingCycleEndDate", "CurrentBillCycleDataUnRatedUsage"]
]
| map(. // "NOT-EXIST")

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

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

need to extract specific string with JQ

I have a JSON file (see below) and with JQ I need to extract the resourceName value for value = mail#mail1.com
So in my case, the result should be name_1
Any idea to do that ?
Because this does not work :
jq '.connections[] | select(.emailAddresses.value | test("mail#mail1.com"; "i")) | .resourceName' file.json
{
"connections": [
{
"resourceName": "name_1",
"etag": "123456789",
"emailAddresses": [
{
"metadata": {
"primary": true,
"source": {
"type": "CONTACT",
"id": "123456"
}
},
"value": "mail#mail1.com",
}
]
},
{
"resourceName": "name_2",
"etag": "987654321",
"emailAddresses": [
{
"metadata": {
"primary": true,
"source": {
"type": "CONTACT",
"id": "654321"
},
"sourcePrimary": true
},
"value": "mail#mail2.com"
}
]
}
],
"totalPeople": 187,
"totalItems": 187
}
One solution is to store the parent object while selecting on the child array:
jq '.connections[] | . as $parent | .emailAddresses // empty | .[] | select(.value == "mail#mail1.com") | $parent.resourceName' file.json
emailAddresses is an array. Use any if finding one element that matches will suffice.
.connections[] | select(any(.emailAddresses[];.value == "mail#mail1.com")).resourceName

Processing JSON with jq - handling array index/name into output

I'm trying to use jq to parse a JSON file for me. I want to get a value from a definition header into the output data in place of an index. A simplified example:
{
"header": {
"type": {
"0": {
"name": "Cats"
},
"3": {
"name": "Dogs"
}
}
},
"data": [
{
"time": "2019-01-01T02:00:00Z",
"reading": {
"0": {"value": 90, "note": "start" },
"3": {"value": 100 }
}
}
]
}
Using a jq command like jq '.data[] | {time: .time, data: .reading[]}' gives me:
"time": "2019-01-01T02:00:00Z",
"data": {
"value": 90,
"note": "start"
}
}
{
"time": "2019-01-01T02:00:00Z",
"data": {
"value": 100
}
}
I need to get "Cats" or "Dogs" into the result, heading towards an SQL insert.
Something like:
{
"time": "2019-01-01T02:00:00Z",
"data": {
"type: "Cats", <- line added
"value": 90,
"note": "start"
}
}
...
Or better yet:
{
"time": "2019-01-01T02:00:00Z",
"Cats": { <- label set to "Cats" instead of "data"
"value": 90,
"note": "start"
}
}
...
Is there a way I can get - what I see as the array index "0" or "3" - to be added as "Cats" or "Dogs"?
Using the built-in function, INDEX, for creating a dictionary allows a straightforward solution as follows:
(.header.type
| INDEX(to_entries[]; .key)
| map_values(.value.name)) as $dict
| .data[]
| (.reading | keys_unsorted[]) as $k
| {time} + { ($dict[$k]) : .reading[$k] }
Output
{
"time": "2019-01-01T02:00:00Z",
"Cats": {
"value": 90,
"note": "start"
}
}
{
"time": "2019-01-01T02:00:00Z",
"Dogs": {
"value": 100
}
}

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)