How retain NESTED JSON structure in PowerShell while using the ConverFrom-JSON and ConvertTo-Json cmdlets - arrays

I have a simple JSON:
{
"config": {
"option": {
"destination": ""
}
}
}
I read this JSON in PowerShell as
$flattended = Get-Content .\aboveJson.json | ConvertFrom-Json
I need to set the value of destination element to some value and then save it back to the same JSON or another JSON while retaining the structure. However, while reading the Nested object I see, PowerShell treated the option element differently and while saving with ConvertTo-Json, I see the output as "option": "#{destination=""}"
Could anyone please help and guide to any articles as to how PowerShell treats this data structure and what should be my way to handle the scenario ?

You shouldn't see this issue with your current example. However, the symptoms you see are due to the number of nested levels in your JSON structure. By default, the ConvertTo-Json command uses a default depth of 2. You can manually set this differently.
$flattened = Get-Content .\aboveJson.json | ConvertFrom-Json
$flattened.config.option.destination = 'new destination'
$flattened | ConvertTo-Json -Depth 10

Related

jq: delete element from array

I have this JSON file and want to delete an element from an array:
{
"address": "localhost",
"name": "local",
"vars": {
"instances": [
"one",
"two"
]
}
}
I am using this command:
jq 'del(.vars.instances[] | select(index("one")))' data.json
The output is:
{
"address": "localhost",
"name": "local",
"vars": {
"instances": [
"two"
]
}
}
So it works as expected, but only with jq v1.6. With jq v1.5 I get this error:
jq: error (at data.json:20): Invalid path expression near attempt to access element 0 of [0]
So what am I doing wrong? Is this a bug or a feature of v1.5? Is there any workaround to get the same result in v1.5?
Thanks in advance
Vince
One portable to work with on both versions would be,
.vars.instances |= map(select(index("one")|not))
or if you want to still use del(), feed the index of the string "one" to the function as below, where index("one") gets the index 0 which then gets passed to delete as del(.[0]) meaning to delete the element at zeroth index.
.vars.instances |= del(.[index("one")])
The implementation of del/1 has proven to be quite difficult and indeed it changed between jq 1.5 and jq 1.6, so if portability across different versions of jq is important, then usage of del/1 should either be restricted to the least complicated cases (e.g., no pipelines) or undertaken with great care.

json / jq : multi-level grouping of sub-elements in an array

i'm writing a script that needs to parse incoming json into line-by-line data, taking information from the json at multiple different levels. i'm using jq to parse the data.
the incoming json is an array of 'tasks'. each task [i.e. each element of the array] is an object that looks like this :
{
"inputData": {
"transfers": [
{
"source": {
"directory": "/path/to/source",
"filename": "somefile.mp3"
},
"target": {
"directory": "/path/to/target",
"filename": "somefile.mp3"
}
},
{
"source": {
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><delivery>content description</delivery>",
"encoding": "UTF-8"
},
"target": {
"directory": "/path/to/target",
"filename": "somefile.xml"
}
}
]
},
"outputData": {
"transferDuration": "00:00:37:10",
"transferLength": 187813298,
},
"updateDate": "2020-02-21T14:37:18.329Z",
"updateUser": "bob"
}
i want to read all of the tasks and, for each one, output a single line composed of the following fields :
task[n].inputData.transfers[].target.filename, task[n].outputData.transferLength, task[n].updateDate
i've got my filter chain to where it will choose the appropriate fields correctly, even to where it will pick the 'correct' single entry from amongst the multiple entries in the task[].inputData.transfers[] array, but when i try to get the output of more than a single element, the chain iterates over the array three times, and i get
task[0].inputData.transfers[].target.filename
task[1].inputData.transfers[].target.filename
task[2].inputData.transfers[].target.filename
...
task[n].inputData.transfers[].target.filename
then the results of the outputData.transferLength field for all elements,
then the results of the updateDate field for all elements.
here is my filter chain :
'(.tasks[].inputData.transfers[] | select(.target.filename | match("[Xx][Mm][Ll]$")).target.filename), .tasks[].outputData.transferLength, .tasks[].updateDate'
i'm thinking there must be some efficient way to group all of these multi-level elements together for each element of the array ; something like a 'with ...' clause, like with tasks[] : blablabla, but can't figure out how to do it. can anyone help ?
The JSON example contained a superfluous , that jq won't accept.
Your example filter chain appears to operate on .tasks[] even though the example appears to be only a single task. So it is not possible to rewrite what you have got into a functioning state. So rather than provide an exact answer to an inexact question, here is the first of the three parts of your filter chain revised:
.inputData.transfers | map(select(.target.filename | match("xml$"; "i")))
See this jqplay snippet.
Rather than write [ .xs[] | select(p) ], just write .xs | map(select(p)).
i finally found the answer. the trick was to pipe the .tasks[] into an expression where the parens were placed around the field elements as a group, which apparently will apply whatever is inside the parens to each element of the array individually, in sequence. then using #dmitry example as a guide, i also placed the elements inside right and left brackets to recreate array elements that i could then select, which could then be output onto 1 line each with | #csv. so the final chain that worked for me is :
.task[] | ([.inputData.transfers[].target.filename, .outputData.transferLength, .updateDate]) | [(.[0],.[2],.[3])] | #csv'
unfortunately i couldn't get match() to work in this invocation, nor sub() ; each of these caused jq to offer a useless error message just before it dumped core.
many thanks to the people who replied.

JSON Array in PowerShell

Am trying to generate the below JSON string in PowerShell:
[
{
"FirstName": "Test",
"LastName": "Account2"
}
]
The code I have at the moment in PowerShell is:
$Body = #{
#{
FirstName='Test'
LastName='Account2'
}
}
The error I get with this is: Missing '=' operator after key in hash literal.
The outer [] is a list in JSON and you're trying to use #{}, which is a hashtable in PowerShell. Use #() which is an array (list) in PowerShell:
$Body = #(
#{
FirstName='Test'
LastName='Account2'
}
)
ConvertTo-Json -InputObject $Body
(and I use -InputObject instead of piping, because PowerShell is obsessed with flattering lists, and drops the list otherwise).
I had some problems adding new items to the Powershell list. I tried to add an item using the .add() function. This returned the error "Collection was of a fixed size."
Adding items to the list is just simple by using the += symbol.
$Body += #{FirstName='Test2'; LastName='Account3'}
That simple.

Trying to add an object to an array of hashtables in powershell

If the answer is out there, I am not able to find it. I am trying to work with Json in powershell, and the target system is looking for an array of hashtables. Each hashtable has the item name as value. Here is how I am creating my array:
$json = #{
update = #{
customfield_11136 = #( #{ setty = #( #{ value="testValue" })})
}
}
The actual array is quite a bit larger, but this is the part I am working on at the moment. I am trying to add an additional value to $json.update.customfield_11136.setty.
Ultimately the output should look something like:
{
"update": {
"customfield_11136": [{
"set": [{
"value": "E0"
}, {
"value": "N0"
}, {
"value": "T0"
}]
}]
}
}
But I need to be able to add the additional values after initial creation.
I have tried every combination I could think of with .add() and +=, but I am not able to get anything to work. I believe this is a punctuation issue on my part, but I am fairly new to working with hashtable arrays, and have tried everything I can think of.
Appreciate any input.
Based on your example this works for me:
$json["update"]["customfield_11136"][0]["setty"] += #{"value"="E0"}
ConvertTo-Json -Depth 5 $json

Get each JSON array value using PHP

I've been trying to read this JSON with PHP:
{
"total_found":"49",
"1":{
"title":"Maze Runner-The Scorch Trials 2015 HD-TS x264-Garmin",
"category":"video",
"seeds":2141,
"leechs":1176,
"torrent_size":1122230176,
"torrent_hash":"29d3e7062825a62abdd877ee96dc3fea41183836"
},
"2":{
"title":"Maze.Runner-The.Scorch.Trials.2015.720P.HD-TS.x264.AC3.HQ.Hive-CM8",
"category":"hdrip",
"seeds":395,
"leechs":1856,
"torrent_size":3999751475,
"torrent_hash":"e1e14a5ccf540a739907db2e1e0d810ecdb8bebc"
}
}
How can I get each title and torrent_size?
The easiest thing to do is to decode the JSON to an array. PHP has a built-in function for this:
$results = json_decode($json_data);
http://php.net/manual/en/function.json-decode.php
To clearly see the array structure, try dumping the variable $results using print_r();, i.e.:
print_r($results);
Then you simply need to access the data using the array.
It will be something like $results[1]['torrent_size'];.

Resources