Get the output in the indicated format without selected data - jq

Using jq, how to get the output in the indicated format without selected groups, e.g. group_3. All data is to be selected from each selected group: name_x.
Input:
{
"groups": {
"group_1": {
"name_1": {
"field_111": "value_111",
"field_112": "value_112",
"field_11n": "value_11n"
},
"name_2": {
"field_121": "value_121",
"field_122": "value_122",
"field_12n": "value_12n"
}
},
"group_2": {
"name_3": {
"field_231": "value_231",
"field_232": "value_232",
"field_23n": "value_23n"
}
},
"group_3": {
"name_4": {
"field_341": "value_341",
"field_342": "value_342",
"field_34n": "value_34n"
}
}
}
}
Ouptut:
name: name_1, group: group_1, field_A_value: value_111, field_B_value: value_112
name: name_2, group: group_1, field_A_value: value_121, field_B_value: value_122
name: name_3, group: group_2, field_A_value: value_231, field_B_value: value_232

Try something like this:
jq --raw-output '
.groups | to_entries[] | select(.key | IN("group_3") | not)
| [.key] + (.value | to_entries[] | [.key, .value[]])
| "name: \(.[1]), group: \(.[0]), field_A_value: \(.[2]), field_B_value: \(.[3])"
' input.json
Demo
If you want to exclude more than just one group, change IN("group_3") to, say, IN("group_3", "group_5", "group_7")

Related

Conditionally output a field?

In this example I only want isGreaterThanOne field to be shown if it's true. Here's what I started with (always shown)
echo '[{"a":5},{"a":1}]' | jq '[.[] | {value:.a, isGreaterThanOne:(.a>1)}]'
I inserted an if statement
echo '[{"a":5},{"a":1}]' | jq '[.[] | {value:.a, X:(if .a>1 then "Y" else "N" end) }]'
Then got stuck trying to move the field into the conditional. Also it seems like I must have an else with an if
echo '[{"a":5},{"a":1}]' | jq '[.[] | {value:.a, (if .a>1 then (K:"Y)" else (L:"N") end) }]'
I want the below as the result (doesn't need to be pretty printed)
[
{
"value": 5,
"X": "Y"
},
{
"value": 1,
}
]
Using if, make one branch provide an empty object {} which wouldn't contain the extra field:
map({value: .a} + if .a > 1 then {X: "Y"} else {} end)
Demo
Alternatively, equip only selected items with the extra field:
map({value: .a} | select(.value > 1).X = "Y")
Demo
Output:
[
{
"value": 5,
"X": "Y"
},
{
"value": 1
}
]

jq Split value on base space and join to one string

I would like to ask for help. I need to split values from key "Text" on base space " " and join to one line. In actually code I calculate with exactly position but if key Text has S10 is show only S1.
My input
[
{
"PartNumber": "5SE32DFVLG002",
"ClassificationNo": "500001",
"StringValue": "R0050SWSW",
"Field": "95001",
"Text": "S1 W1 cr.sec+colour"
},
{
"PartNumber": "5SE32DFVLG002",
"ClassificationNo": "500001",
"StringValue": "R0050SWSW",
"Field": "95004",
"Text": "S1 W10 cr.sec+colour"
}
]
My actually condition in jq play
[.Oslm[] | select(.ClassificationNo=="500001" and .StringValue!="") |
{PartNumber,ClassificationNo,StringValue,Field,Text}] |
sort_by(.Field) | .[] | [.PartNumber,.ClassificationNo,
.Field[3:5],.Text[0:2] + "-" + .Text[3:5] + .StringValue[0:1], "Test
", .StringValue[1:10]] | join(";")
Actual result
5SE32DFVLG002;500001;95001;S1-W1R;TEST;0050SWSW
5SE32DFVLG002;500001;95004;S1-W1R;TEST;0050SWSW
I would like to have this result
5SE32DFVLG002;500001;95001;S1-W1R;TEST;0050SWSW
5SE32DFVLG002;500001;95004;S1-W10R;TEST;0050SWSW
Modify the part involving generation of .Text to something simpler using split() method in jq that can be used to split on a single white-space. This way, you are not reliant on the length of the sub-fields you want to extract
( .Text | split(" ") | .[0] + "-" + .[1] ) + .StringValue[0:1]
i.e. with full code
.[] | [ select( .ClassificationNo =="500001" and .StringValue != "" ) |
{
PartNumber,
ClassificationNo,
StringValue,
Field,
Text
} ] |
sort_by(.Field) |
map(
.PartNumber,
.ClassificationNo,
.Field[3:5],
( .Text | split(" ") | .[0] + "-" + .[1] ) + .StringValue[0:1],
"Test", .StringValue[1:10]
) |
join(";")
demo at jqplay

Extract nested properties from an array of objects

I have the following JSON file :
{
"filter": [
{
"id": "id_1",
"criteria": {
"from": "mail#domain1.com",
"subject": "subject_1"
},
"action": {
"addLabelIds": [
"Label_id_1"
],
"removeLabelIds": [
"INBOX",
"SPAM"
]
}
},
{
"id": "id_2",
"criteria": {
"from": "mail#domain2.com",
"subject": "subject_1"
},
"action": {
"addLabelIds": [
"Label_id_2"
],
"removeLabelIds": [
"INBOX",
"SPAM"
]
}
}
]
}
And I would like to extract emails values : mail#domain1.com and mail#domain2.com
I have tried this command:
jq --raw-output '.filter[] | select(.criteria.from | test("mail"; "i")) | .id'
But does not work, I get this error :
jq: error (at <stdin>:1206): null (null) cannot be matched, as it is
not a string exit status 5
Another point : how to display the value of "id" key, where "from" key value = mail#domain1.com ?
So in my file id = id_1
Do you have an idea ?
If you only need to extract the emails from .criteria.from then this filter is enough as far as I can tell:
jq --raw-output '.filter[].criteria.from' file.json
If some objects don't have a criteria object then you can filter out nulls with:
jq --raw-output '.filter[].criteria.from | select(. != null)' file.json
If you want to keep the emails equal to "mail#domain1.com":
jq --raw-output '.filter[].criteria.from | select(. == "mail#domain1.com")' file.json
If you want to keep the emails that start with "mail#":
jq --raw-output '.filter[].criteria.from | select(. != null) | select(startswith("mail#"))' file.json
I would like to extract emails values
There is a wide spectrum of possible answers, with these
amongst the least specific with respect to where in the JSON the email addresses occur:
.. | objects | .from | select(type=="string")
.. | strings | select(test("#([a-z0-9]+[.])+[a-z]+$"))

jq not getting expected output

My JSON looks like this.
"[{
changes": [
{
"change": "{users=[7], submitted=true}",
"date": "2016-11-13T14:34:27.353Z",
"user": "abcd"
}
]
}]
Expected Output:
{
id: null,
date: "2016-11-13T14:34:27.353Z",
type: "submission",
user: abcd,
_processDate: todaysDate
}
JQ I tried
[.[][] as $source |
$source.changes[] as $log |
$log.change |
{
submitted: .| (scan("submitted=(?<submitted>[^,}]+)") // [""] ) | .[0],
rejected: .| (scan("rejected=(?<rejected>[^,}]+)") // [""] ) | .[0]
} as $change |
[
(
select($change.submitted == "true") |
{
id: $source.id,
date: $log.date,
type: "submission",
user: $log.user,
_processDate: now | todate
}),
(select($change.rejected == "true") |
{
id: $source.id,
date: $log.date,
type: "rejection",
user: $log.user,
_processDate: now | todate
}
)
] |
.[]]
There could 'rejections' in the json and the output should display the rejections .
My JQ is not yielding expected output.
Any pointers on how to fix this query.
Thank you for your help.
Appreciate it.
I'd take a completely different approach and do this instead.
(now | todate) as $_processDate | [
.[].changes[]
| (.change
| scan("\\b(submitted|rejected)=true\\b")[]
| {submitted:"submission",rejected:"rejection"}[.]) as $type
| {id, date, $type, user, $_processDate}
]
First take note of the current date at the beginning. Then determine what type of change it is. Assuming that "submitted" and "rejected" (or other "types") are mutually exclusive, easier to match on the key name. Then build up the result. This will keep the results in an array.
https://jqplay.org/s/S65ySzbF30

How to avoid record duplication in jq

I've the following Json :
{
"hits": {
"hits": [
{
"_source": {
"offers_data": [
{
"base_price": 198.89,
"shop_id": 2002,
"shop_name": "TheOtherShop"
},
{
"base_price": 223,
"shop_id": 2247,
"shop_name": "MainShop"
},
{
"base_price": 225,
"shop_id": 2247,
"shop_name": "MainShop"
}
],
"search_result_data": {
"identifiers": {
"id": 32116
},
"shop": {
"id": 2247,
"name": "MainShop"
}
}
}
}
]
}
}
I'm writing the following command :
jq -c --raw-output '.hits.hits[]|{products_ids: ._source.search_result_data.identifiers.id,
best_shop_id: ._source.search_result_data.shop.id,
best_shop_name: (if ._source.search_result_data.shop.id>0 then ._source.search_result_data.shop.id as $shop_id|._source.offers_data[]|select(.shop_id==$shop_id).shop_name else "" end),
best_offer_base_price: (if ._source.search_result_data.shop.id>0 then ._source.search_result_data.shop.id as $shop_id|._source.offers_data[]|select(.shop_id==$shop_id).base_price else "" end)}'
and I get this result :
{"products_ids":32116,"best_shop_id":2247,"best_shop_name":"MainShop","best_offer_base_price":223}
{"products_ids":32116,"best_shop_id":2247,"best_shop_name":"MainShop","best_offer_base_price":225}
{"products_ids":32116,"best_shop_id":2247,"best_shop_name":"MainShop","best_offer_base_price":223}
{"products_ids":32116,"best_shop_id":2247,"best_shop_name":"MainShop","best_offer_base_price":225}
As you can see I get 2 duplicates : Of course I've two offers from MainShop, so it's normal that I get 2 records, but if I'm also fetching the base prices, the it duplicates the result again. In my real world case I get 32 records instead of 2 legitimate ones, because I'm fetching other fields. So I'd like to avoid this extra duplication each time I fetch a field.
The icing on the cake would be to be able to only get one record, the one where amongst Mainshop offers the base_price is the minimum.
Thanks
Icing
... the one where the base_price is the minimum.
The following two interpretations of the problem both assume we can take, as the "minimum" item, any of the admissible items that has the minimal value.
First Interpretation of the original question
.hits.hits[]._source
| (.offers_data | min_by(.base_price)) as $min_offers_data
| .search_result_data
| {products_ids: .identifiers.id}
+ ($min_offers_data
| {best_shop_id: .shop_id,
best_shop_name: .shop_name,
best_offer_base_price: .base_price})
Output:
{
"products_ids": 32116,
"best_shop_id": 2002,
"best_shop_name": "TheOtherShop",
"best_offer_base_price": 198.89
}
Second Interpretation
Restrict consideration to .search_result_data.shop.id:
.hits.hits[]._source
| (.search_result_data.shop.id) as $shop
| (.offers_data | map(select(.shop_id == $shop)) | min_by(.base_price)) as $min_offers_data
| .search_result_data
| {products_ids: .identifiers.id}
+ ($min_offers_data
| {best_shop_id: .shop_id,
best_shop_name: .shop_name,
best_offer_base_price: .base_price})
Output
{
"products_ids": 32116,
"best_shop_id": 2247,
"best_shop_name": "MainShop",
"best_offer_base_price": 223
}

Resources