Re-order nested json with jq - json

I have this simple JSON which has a name and a nested info with telephone and address, but now I want my address to show first before telephone. How do I do this with jq?
Sample:
jq . sample.json
{
"name": "john",
"info": {
"telephone": "444-5555",
"address": "1234 Main st"
}
}
{
"name": "jane",
"info": {
"telephone": "222-3333",
"address": "1234 Eagle st"
}
}
Ultimately, I want address before telephone:
{
"name": "john",
"info": {
"address": "1234 Main st"
"telephone": "444-5555",
}
}
So I would do something like this:
jq ". | {name: .name, info: [.info.address, .info.telephone]}" sample.json
But this would give me instead:
{
"name": "john",
"info": [
"1234 Main st",
"444-5555"
]
}
{
"name": "jane",
"info": [
"1234 Eagle st",
"222-3333"
]
}

Oops, it was easy as:
jq ". | {name: .name, info: {address: .info.address, telephone: .info.telephone}}" sample.json
Result:
{
"name": "john",
"info": {
"address": "1234 Main st",
"telephone": "444-5555"
}
}
{
"name": "jane",
"info": {
"address": "1234 Eagle st",
"telephone": "222-3333"
}
}

Or just: .info |= {address,telephone}

Related

I need to retrieve the index(number 1) information in mongodb compass

I just need to query all information of the doctor in the first index.
Here is my sample XML data
Here is my sample JSON data:
Both XML and JSON data are same. I just converted the XML to JSON format.
I have more documents like this.
I tried this query in this image
this query showing all information but I just need first doctors information.
I also tried in command prompt.Here is the query done in cmd
Here is my sample JSON code block: but I have more similar documents
{
"doctors": {
"doctor":[
{
"ssn": "257-79-xxxx",
"name": "Mavis Bxx",
"address": "xxxx Rusk Drive",
"country": "France",
"email": "",
"phone": "",
"patients": {
"patient": [
{
"gender": "Male",
"name": "Itch xxxx",
"address": "xx Cottonwood Avenue",
"revenue": "254",
"_country": "Spain",
"_id": "27"
},
{
"gender": "Male",
"name": "Damon xxxxx",
"address": "xx David Trail",
"revenue": "370",
"_country": "Germany",
"_id": "21"
}
]
},
"_id": "6"
},
{
"ssn": "179-45-xxxx",
"name": "Tobie Conxxxx",
"address": "x Comanche Center",
"country": "Spain",
"email": "tconringh#xxx.xxx",
"phone": "+86 998 262 xxxx",
"patients": {
"patient": {
"gender": "Male",
"name": "Vergil Tome",
"address": "x Melody Drive",
"revenue": "254",
"_country": "Germany",
"_id": "15"
}
},
"_id": "18"
},
{
"ssn": "777-59-xxxx",
"name": "Gertrud Macxxxx",
"address": "x Buell Drive",
"country": "USA",
"email": "gmaclaig2#xxx.com",
"phone": "+62 975 394 xxxx",
"patients": {
"patient": [
{
"gender": "Non-binary",
"name": "Dre Skxxxx",
"address": "x Becker Circle",
"revenue": "400",
"_country": "Germany",
"_id": "20"
},
{
"gender": "Female",
"name": "Arleyne Lestxxxx",
"address": "xx Farragut Court",
"revenue": "225",
"_country": "France",
"_id": "22"
}
]
},
"_id": "3"
}
You needs to change your collect data format. Your current format is single big size data. Not a quarriable format.
So
From current format
{
"doctors": {
"docker": [
{
...
"patients": {
"patient": [
{
...
},
{
...
}
]
},
},
{
...
}
]
}
}
To this format
[
{
...
"patients": [
{
...
},
{
...
}
]
},
{
...
}
]
Test JSON
[
{
"ssn": "2xx-7x-4xxx",
"name": "Mavis Bxxxed",
"address": "9xxx Rusk Drive",
"country": "France",
"email": "",
"phone": "",
"patients": [
{
"gender": "Male",
"name": "Itch Txxx",
"address": "5xx Cottonwood Avenue",
"revenue": "25x",
"_country": "Spain",
"_id": "27"
},
{
"gender": "Male",
"name": "Damon Wxxx",
"address": "09xx Dxxxx Trail",
"revenue": "370",
"_country": "Germany",
"_id": "21"
}
],
"_id": "6"
},
{
"ssn": "19-45-xxxx",
"name": "Tobie Coxxxx",
"address": "8x Comxxxx Center",
"country": "Spain",
"email": "tconxxxxx#usa.gov",
"phone": "",
"patients": [
{
"gender": "Male",
"name": "Some one",
"address": "1 Mexxxx Drive",
"revenue": "254",
"_country": "Germany",
"_id": "15"
}
],
"_id": "18"
}
]
In Compass View after add data upper data
Find doctor by name query
{ name: "Mavis Bxxxed" }
Find doctor by patient name
{ "patients.name": "Some one" }
If same search with this query
{ "patients.name": "Itch Txxx" }
OR
{ "patients.name": "Damon Wxxx" }
will same result to find the first docker (Mavis Bxxxed)
Due to it's patients start [ and end ]. it is array type a single size of data.
You can filter by project option
{
patients: {
$filter:
{
input: "$patients",
cond: { $eq: [ "$$patient.name", "Itch Txxx"] },
as: "patient"
}
}
}
OR shows only address
{ "patients.address" : 1 }

JQ merge WooCommerce REST API responce

Im trying to parse data from woocommerce from linux console.
Need to take only shipping info and item names with quantity.
im making curl request to wp-json/wc/v2/orders/ORDER_ID
then
jq '{order_id:.id,ship_info:.shipping,items: (.line_items[] | {name , quantity} ) }'
If order contains two items, jq will return two objects
example:
{
"order_id": 1234,
"ship_info": {
"first_name": "Sam",
"last_name": "Fisher",
"company": "",
"address_1": "24 Mega Drive",
"address_2": "",
"city": "Eglinton",
"state": "WA",
"postcode": "6032",
"country": "AU",
"phone": ""
},
"items": {
"name": "Black T-shirt",
"quantity": 1
}
}
{
"order_id": 1234,
"ship_info": {
"first_name": "Sam",
"last_name": "Fisher",
"company": "",
"address_1": "24 Mega Drive",
"address_2": "",
"city": "Eglinton",
"state": "WA",
"postcode": "6032",
"country": "AU",
"phone": ""
},
"items": {
"name": "White T-shirt",
"quantity": 1
}
}
I want merge items and use item's name as a key and item's qty as a value. Please advice how to get output like this
{
"order_id": 1234,
"ship_info": {
"first_name": "Sam",
"last_name": "Fisher",
"company": "",
"address_1": "24 Mega Drive",
"address_2": "",
"city": "Eglinton",
"state": "WA",
"postcode": "6032",
"country": "AU",
"phone": ""
},
"items": {
"White T-shirt": "1",
"Black T-shirt": "1"
}
}
With your current jq query you are iterating over the items inside a generated object. That's why you receive one object per item. Rather than merging them afterwards, don't separate them in the first place.
If you changed your query from
jq '{
order_id: .id,
ship_info: .shipping,
items: (.line_items[] | {name, quantity})
}'
to just
jq '{
order_id: .id,
ship_info: .shipping,
items: .line_items
}'
you'd probably already see that .line_items is actually an array.
To transform it according to your desired output, change that line to one of the followings. They should all yield the same result.
items: (.line_items | map({(.name): .quantity}) | add)
items: (INDEX(.line_items[]; .name) | map_values(.quantity))
items: (reduce .line_items[] as $i ({}; .[$i.name] = .quantity))

select elements of an array and update it in-place

Given the following JSON,
I'm trying to filter out items in the cars array where the item's comments array is null:
.cars[] | select(.comments == null)
or the item's comments array exists and any of the comments objects don't contain the value "FooBar"
.cars[] | select( select(.comments != null) | (any(.comments[]; index("FooBar")) | not) )
while retaining the original structure.
With jq I can figure out how to create the critera I want to filter down to but what I can't wrap my head around is how to make that apply to the top level items.
JSON input:
{
"person": {
"first_name": "Bob",
"last_name": "Smith"
},
"addresses": [
{
"home": {
"line1": "123",
"line2": "A st."
}
},
{
"work": {
"line1": "456",
"line2": "B st."
}
}
],
"cars": [
{
"make": "Honda",
"model": "Civic"
},
{
"make": "Honda",
"model": "Accord"
},
{
"make": "Honda",
"model": "Pilot",
"comments": [
"Comment 1",
"Comment 2",
"FooBar"
]
},
{
"make": "Honda",
"model": "Passport",
"comments": [
"Comment 3",
"Comment 4"
]
}
]
}
JSON Outut, same as the input but the oject with the comment array containg the value "FooBar" is filtered out:
{
"person": {
"first_name": "Bob",
"last_name": "Smith"
},
"addresses": [
{
"home": {
"line1": "123",
"line2": "A st."
}
},
{
"work": {
"line1": "456",
"line2": "B st."
}
}
],
"cars": [
{
"make": "Honda",
"model": "Civic"
},
{
"make": "Honda",
"model": "Accord"
},
{
"make": "Honda",
"model": "Passport",
"comments": [
"Comment 3",
"Comment 4"
]
}
]
}
Just use the update-assignment operator (|=).
.cars |= map(select(.comments))
.cars |= map(select(.comments and any(.comments[]; index("FooBar")) | not))

Splitting nested arrays as separate entities

I have some JSON data which contains attributes and some array elements. I would like to push a given set of fields into the array elements and then separate the arrays as separate entities.
Source data looks like this
[
{
"phones": [
{
"phone": "555-555-1234",
"type": "home"
},
{
"phone": "555-555-5678",
"type": "mobile"
}
],
"email": [
{
"email": "a#b.com",
"type": "work"
},
{
"email": "x#c.com",
"type": "home"
}
],
"name": "john doe",
"year": "2012",
"city": "cupertino",
"zip": "555004"
},
{
"phones": [
{
"phone": "555-666-1234",
"type": "home"
},
{
"phone": "555-666-5678",
"type": "mobile"
}
],
"email": [
{
"email": "a#b.com",
"type": "work"
},
{
"email": "x#c.com",
"type": "home"
}
],
"name": "jane doe",
"year": "2000",
"city": "los angeles",
"zip": "555004"
}
]
I expect a result like this
{
"person": [
{
"name": "john doe",
"year": "2012",
"city": "cupertino",
"zip": "555004"
},
{
"name": "jane doe",
"year": "2000",
"city": "los angeles",
"zip": "555004"
}
],
"phones": [
{
"name": "john doe",
"year": "2012",
"phone": "555-555-1234",
"type": "home"
},
{
"name": "john doe",
"year": "2012",
"phone": "555-555-5678",
"type": "mobile"
},
{
"name": "jane doe",
"year": "2000",
"phone": "555-666-1234",
"type": "home"
},
{
"name": "jane doe",
"year": "2000",
"phone": "555-666-5678",
"type": "mobile"
}
],
"email": [
{
"name": "john doe",
"year": "2012",
"email": "a#b.com",
"type": "work"
},
{
"name": "john doe",
"year": "2012",
"email": "x#c.com",
"type": "home"
},
{
"name": "jane doe",
"year": "2000",
"email": "a#b.com",
"type": "work"
},
{
"name": "jane doe",
"year": "2000",
"email": "x#c.com",
"type": "home"
}
]
}
I have been able to get the desired result, but I can't make it work in a generic way.
experiment on jqterm
The code below achieves the job, but I would like to pass the array of columns to be injected into the child arrays, the name of the primary result and an array containing the array field names.
["phones", "email"] as $children
| ["name", "year"] as $ids
|{person: map(with_entries(
. as $data | select($children|contains([$data.key])|not)
))}
+ {"phones": split_child($children[0];$ids)}
+ {"email": split_child($children[1];$ids)}
It's a lot more easier to achieve this using multiple reduces, like:
def split_data($parent; $ids; $arr_cols):
($arr_cols | map([.])) as $p
| reduce .[] as $in ({}; .[$parent] += [$in | delpaths($p)]
| (reduce $ids[] as $k ({}; . + {($k): $in[$k]}) as $s
| reduce $arr_cols[] as $k (.; .[$k] += [$in[$k][] + $s])
);
split_data("person"; ["name", "year"]; ["phones", "email"])
Here's a straightforward solution to the generic problem (it uses reduce only once, in a helper function). To understand it, it might be helpful to see it as an abstraction of this concrete solution:
{ person: [.[] | {name, year, city, zip} ]}
+ { phones: [.[] | ({name, year} + .phones[]) ]}
+ { email: [.[] | ({name, year} + .email[]) ]}
Helper function
Let's first define a helper function for constructing an object by selecting a set of keys:
def pick($ary):
. as $in
| reduce $ary[] as $k ({};
. + {($k): $in[$k]});
split_data
Here finally is the function that takes as arguments the $parent, $ids, and columns of interest. The main complication is ensuring that the supplemental keys ("city" and "zip") are dealt with in the proper order.
def split_data($parent; $ids; $arr_cols):
(.[0]|keys_unsorted - $arr_cols - $ids) as $extra
| { ($parent): [.[] | pick($ids + $extra)] }
+ ([$arr_cols[] as $k
| {($k): [.[] | pick($ids) + .[$k][]] }] | add) ;
The invocation:
split_data("person"; ["name", "year"]; ["phones", "email"])
produces the desired result.

Combining Nested Json using PowerShell

I have the following Json script:
{
"merchant_info": {
"email": "merchant#example.com",
"first_name": "David",
"last_name": "Larusso",
"business_name": "Mitchell & Murray",
"phone": {
"country_code": "001",
"national_number": "4085551234"
},
"address": {
"line1": "1234 First Street",
"city": "Anytown",
"state": "CA",
"postal_code": "98765",
"country_code": "US"
}
},
"billing_info": [{
"email": "bill-me#example.com",
"first_name": "Stephanie",
"last_name": "Meyers"
}
],
"shipping_info": {
"first_name": "Stephanie",
"last_name": "Meyers",
"address": {
"line1": "1234 Main Street",
"city": "Anytown",
"state": "CA",
"postal_code": "98765",
"country_code": "US"
}
},
"items": [{
"name": "Zoom System wireless headphones",
"quantity": 2,
"unit_price": {
"currency": "USD",
"value": "120"
},
"tax": {
"name": "Tax",
"percent": 8
}
}, {
"name": "Bluetooth speaker",
"quantity": 1,
"unit_price": {
"currency": "USD",
"value": "145"
},
"tax": {
"name": "Tax",
"percent": 8
}
}
],
"discount": {
"percent": 1
},
"shipping_cost": {
"amount": {
"currency": "USD",
"value": "10"
}
},
"note": "Thank you for your business.",
"terms": "No refunds after 30 days."
}
And I want to use PowerShell to get the following Record and export it to CSV:
So far I created the following Script:
$JsonFile = "C:\Users\me\Documents\myfile.json"
$OutputFile = "C:\Users\me\Documents\newtext.csv"
Get-Content -Path $OutputFile
$json = ConvertFrom-Json (Get-Content $JsonFile -Raw)
$json.merchant_info | Select "first_name","last_name",#{Label = "phone"; Expression = {$_.phone.national_number}} |
Export-Csv $OutputFile -NoTypeInformation
I am able to bring values from (Merchant_info, Shipping_info, item) separetely but how do I bring it all in combined like in my screen shot above.
but how do I bring it all in combined like in my screen shot above.
We can only guess; assuming this entire json block is one order, with one merchant and one customer, but multiple items, then each row is an item. So start with that as the input:
Create an output record (PSCustomObject) with the repeated data, and then the individual item data:
$json.items | ForEach-Object {
[PSCustomObject]#{
MerchantInfoFirstName = $json.merchant_info.first_name
MerchantInfoLastName = $json.merchant_info.last_name
MerchantInfoPhoneNumber = $json.merchant_info.phone.national_number
ShippingInfoFirstName = $json.shipping_info.first_name
ShippingInfoLastName = $json.shipping_info.last_name
ItemName = $_.name
ItemQuantity = $_.quantity
}
} | Export-Csv ... etc.