i have an array converted to a json ($user_data_JSON = $user_data | ConvertTo-Json) in powershell which looks like this
$user_data_JSON
{
[
{
"targetId": "5007Y00000K5nkjQAB",
"login": "login1",
"password": "scRHDztkKbO"
},
{
"targetId": "5007Y00000MNbDvQAL",
"login": "login2",
"password": "scRHDztkKbO"
}
]
}
But i need to modify it like this with a KEY value on top:
$user_data_JSON
{
"logins":[
{
"targetId": "5007Y00000K5nkjQAB",
"login": "login1",
"password": "scRHDztkKbO"
},
{
"targetId": "5007Y00000MNbDvQAL",
"login": "login2",
"password": "scRHDztkKbO"
}
]
}
How can I manage to achieve this?
I've already tried to create a new array object, add the key and convert it to a json file like this:
$jsonBase = #{}
$list = New-Object System.Collections.ArrayList
$list.Add("Foo")
$list.Add("Bar")
$jsonBase.Add("Data",$list)
$jsonBase | ConvertTo-Json
To get something like this:
{
"Data": [
"Foo",
"Bar"
]
}
but when I convert my array to a json again, it looks kind of trunkated:
$jsonBase | ConvertTo-Json -Depth 10
{
"logins": [
"[\r\n {\r\n \"targetId\": \"5007Y00000K5nkjQAB\",\r\n \"login\": \"login1\",\r\n \"password\": \"scRHDztkKbO\"\r\n },\r\n {\r\n
\"targetId\": \"5007Y00000MNbDvQAL\",\r\n \"login\": \"login2\",\r\n \"password\": \"scRHDztkKbO\"\r\n },"
]
}
How can I get a propoer JSON object?
Thanks
Don't use the JSON (text) representation of your array ($user_data_JSON), use its original, object form ($user_data) to construct a wrapper object with the desired top-level property:
[pscustomobject] #{ logins = $user_data } | ConvertTo-Json -Depth 10
As for what you tried:
If you use a preexisting JSON string as the value of property to be converted to JSON with ConvertTo-Json, it is treated like any other string value, resulting in the representation you saw, with " characters escaped as \" and (CRLF) newlines as \r\n
A simple example:
[pscustomobject] #{
foo = '{ "bar":
"baz" }'
} | ConvertTo-Json
Output (note how the foo property value became a single-line string with " and newlines escaped):
{
"foo": "{ \"bar\": \n \"baz\" }"
}
Ok, i spent way to much time on this.
Using jq, i want to test if an element exist in an array, if yes being able to mofify this element, if not adding this element to that array
I have read
Update one value in array of dicts, using jq
How to check if element exists in array with jq
Which gave hints But i am stuck
Let say i have a json file like :
{
"LOGIN":"user",
"COPY": [
{
"CHAINLIST":"chain1",
"ELEMENT": [ "element1-1","element1-2" ]
},
{
"CHAINLIST":"chain2",
"ELEMENT": [ "element2-1","element2-2" ]
}
]
}
I Would like to add elements to the COPY array based in the CHAINLIST id , let say those 3 elements :
//ELEM A
{
"CHAINLIST":"chain3",
"ELEMENT": [ "element3-1" ]
}
//ELEM B
{
"CHAINLIST":"chain2",
"ELEMENT": [ "element2-1","element2-3" ]
}
//ELEM C
{
"CHAINLIST":"chain1",
"ELEMENT": [ "element1-1","element1-2" ]
}
ELEM A has the CHAINLIST id chain3 who doesn't exit in the COPY Array _> let's add it
ELEM B Is already present in the COPY aray, I want to update the ELEMENT array
content with the new value
ELEM C Already exist and is up to date, i don't need to do anything.
In my example the final json object would be
{
"LOGIN":"user",
"COPY": [
{
"CHAINLIST":"chain1",
"ELEMENT": [ "element1-1","element1-2" ]
},
{
"CHAINLIST":"chain2",
"ELEMENT": [ "element2-1","element2-2","element2-3" ]
},
{
"CHAINLIST":"chain3",
"ELEMENT": [ "element3-1"]
}
]
}
I am using jq The procedure to add the element Elem to the object Obj would be :
Elem.CHAINLIST exist in Obj.COPY [] ?
yes : add Elem.ELEMENT to Obj.ELEMENT[] with unique to qvoid duplicates
no : add Elem to Obj.COPY[]
The best i get is
(if .COPY[]? | select (.CHAINLIST=="chain3") == "" then . else .COPY[.COPY | length ] |= . + { "CHAINLIST":"chain3","ELEMENT":[ "element3-1"]} end )
But select (.CHAINLIST=="chain3") == "" return nothing I i can figure out how to test if empty.
Thank you for your time !
The following solution uses the built-in function INDEX/2 to create convenient and efficient representations
of the collections of CHAINLIST-ELEMENT objects, together with a bespoke function, augment/1, for combining elements.
It is assumed that the objects defining the updates are presented as an array in the file edits.json.
< input.json jq --argfile edits edits.json '
# Use `unique` to combine the .ELEMENT fields
def augment($b):
reduce ($b|keys_unsorted[]) as $key (.;
.[$key].ELEMENT = (.[$key].ELEMENT + $b[$key].ELEMENT | unique));
(INDEX($edits[];.CHAINLIST) | map_values(del(.CHAINLIST))) as $edits
| (INDEX(.COPY[]; .CHAINLIST) | map_values(del(.CHAINLIST))) as $COPY
| .COPY |= ($COPY
| augment($edits)
| to_entries
| map( { CHAINLIST: .key, ELEMENT: .value.ELEMENT} ))
Output: as specified in the question.
Note: if the objects defining the updates are presented as a sequence of objects in a file, you could use the above solution with --slurpfile instead of --argfile.
I'm totally brand new to JSON and jq so this might seem like a simple question.
I'd like to change an array of numbers into an array of objects with a key for each value (number).
Let's say I have a JSON file like this:
{
"foo": [1519739200, 1519739600, 1519740000]
}
Then my desired output would be:
{
"foo": [
{
"id": 1519739200
},
{
"id": 1519739600
},
{
"id": 1519740000
},
]
}
So far everything I've seen was connected with adding new keys with values to existing object or merging two arrays into few objects. I know that I can add more keys into already existing object but how can I add keys to an array? I assume I have to change array elements into objects first but how do I do it?
Thank you for answer.
Check this,
https://jqplay.org/s/xF9DyVbhXD
{ foo : [ { id : .foo[] } ] }
There are a few ways to go about it.
First you want to create a new object for each item in foo:
$ jq -c '{ id: .foo[] }'
{"id":1519739200}
{"id":1519739600}
{"id":1519740000}
You can then rebuild the "shape" you had - first with [ ... ]
$ jq -c '[ { id: .foo[] } ]'
[{"id":1519739200},{"id":1519739600},{"id":1519740000}]
Then the { foo: }
$ jq -c '{ foo: [ { id: .foo[] } ] }'
{"foo":[{"id":1519739200},{"id":1519739600},{"id":1519740000}]}
Another option is to use |= to modify/update .foo directly.
$ jq -c '.foo |= [{id: .[]}]'
{"foo":[{"id":1519739200},{"id":1519739600},{"id":1519740000}]}
I'm trying to format some data that consists of json objects that includes some identifying information along with an array of one or more json objects, I would like the result to be one line of data per array element where each line should include some fields from the array element and some fields from the identifying information.
My sample data is below:
{
"eventCreation": {
"timeStamp": "2020-06-06T15:07:20Z",
"epoch": 1591456040
},
"eventData": {
"applName": "SampleApp",
"channelName": "SYSTEM.DEF.SVRCONN",
"connectionName": "127.0.0.1",
"channelType": "Svrconn",
"remoteProduct": "MQJM",
"remoteVersion": "09010005",
"activityTrace": [
{
"operationId": "Get",
"operationTime": "11:07:18",
"qmgrOpDuration": 102,
"reasonCode": {
"name": "No Msg Available",
"value": 2033
},
"objectName": "SYSTEM.DEFAULT.LOCAL.QUEUE"
},
{
"operationId": "Cb",
"operationTime": "11:07:18",
"qmgrOpDuration": 10,
"reasonCode": {
"name": "None",
"value": 0
},
"objectName": "SYSTEM.DEFAULT.LOCAL.QUEUE"
},
{
"operationId": "Cb",
"operationTime": "11:07:18",
"qmgrOpDuration": 12,
"reasonCode": {
"name": "None",
"value": 0
},
"objectName": "SYSTEM.DEFAULT.LOCAL.QUEUE"
}
]
}
}
I would like to get an output like this:
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","11:07:18","Get",102,"SYSTEM.DEFAULT.LOCAL.QUEUE",2033
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","11:07:18","Cb",10,"SYSTEM.DEFAULT.LOCAL.QUEUE",0
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","11:07:18","Cb",12,"SYSTEM.DEFAULT.LOCAL.QUEUE",0
I can pick any one element of the array and get it to print 3 lines, but if I add a 2nd element it will print 9 lines, 3rd element prints 27, etc.
For example:
jq -r '{channelName: .eventData.channelName, channelType: .eventData.channelType, connectionName: .eventData.connectionName, applName: .eventData.applName, remoteProduct: .eventData.remoteProduct, remoteVersion: .eventData.remoteVersion, operationId: .eventData.activityTrace[].operationId}|[.[]]|#csv' TEST.json
Will produce this:
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Get"
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb"
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb"
If I add a second like this:
jq -r '{channelName: .eventData.channelName, channelType: .eventData.channelType, connectionName: .eventData.connectionName, applName: .eventData.applName, remoteProduct: .eventData.remoteProduct, remoteVersion: .eventData.remoteVersion, operationId: .eventData.activityTrace[].operationId, qmgrOpDuration: .eventData.activityTrace[].qmgrOpDuration}|[.[]]|#csv' TEST.json
Will produce this:
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Get",102
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Get",10
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Get",12
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb",102
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb",10
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb",12
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb",102
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb",10
"SYSTEM.DEF.SVRCONN","Svrconn","127.0.0.1","SampleApp","MQJM","09010005","Cb",12
Using your approach, the following is a solution:
.eventData
| ({channelName, channelType, connectionName, applName, remoteProduct, remoteVersion}
+ ( .activityTrace[]
| { operationTime, operationId, qmgrOpDuration, objectName, v: .reasonCode.value}))
| [.[]]
| #csv
The key is to iterate just once.
Notice also that this solution achieves its brevity in part by using the fact that {foo: .foo} can be abbreviated to {foo}.
A slightly more efficient approach
.eventData
| [.channelName, .channelType, .connectionName, .applName, .remoteProduct, .remoteVersion]
+ ( .activityTrace[]
| [.operationTime, .operationId, .qmgrOpDuration, .objectName, .reasonCode.value] )
| #csv
.operationTime first
.eventData
| [.channelName, .channelType, .connectionName, .applName, .remoteProduct, .remoteVersion] as $x
| ( .activityTrace[]
| [.operationTime]
+ $x
+ [.operationId, .qmgrOpDuration, .objectName, .reasonCode.value] )
| #csv
I have a json file that I use for work that I need to parse that is in the following format:
(^)#(^)#(^)#(^)bminter#ubuntu:~$ cat jqtest
{
"files":[
{
"BLOCK1":{
"SUBBLOCK1":{
"akey1":"avalue1",
"bkey1":"bvalue1",
"ckey1":"cvalue1"
},
"dkey1":"dvalue1",
"key":"evalue1"
}
},
{
"BLOCK-2":{
"SUBBLOCK2":{
"akey2":"avalue2",
"bkey2":"bvalue2"
},
"ckey2":"cvalue2",
"key":"dvalue2"
}
},
{
"BLOCK-A":{
"SUBBLOCK2":{
"akey2":"avalue2",
"bkey2":"bvalue2"
},
"ckey2":"cvalue2",
"key":"dvalue2"
}
}],
"NOBLOCK":"value",
"key":"NOBLOCKvalue"
}
So it's an array nested within a json file. jq .[] jqtest gives me everything in the file. Even the data outside the array. Except, outside the array, I'm only given the values not the keys:
(^)#(^)#(^)#(^)bminter#ubuntu:~$ jq .[] jqtest
[
{
"BLOCK1": {
"SUBBLOCK1": {
"akey1": "avalue1",
"bkey1": "bvalue1",
"ckey1": "cvalue1"
},
"dkey1": "dvalue1",
"key": "evalue1"
}
},
{
"BLOCK-2": {
"SUBBLOCK2": {
"akey2": "avalue2",
"bkey2": "bvalue2"
},
"ckey2": "cvalue2",
"key": "dvalue2"
}
},
{
"BLOCK-A": {
"SUBBLOCK2": {
"akey2": "avalue2",
"bkey2": "bvalue2"
},
"ckey2": "cvalue2",
"key": "dvalue2"
}
}
]
"value"
"NOBLOCKvalue"
(^)#(^)#(^)#(^)bminter#ubuntu:~$
Beyond that I can't access any block inside the array:
(^)#(^)#(^)#(^)bminter#ubuntu:~$ jq '.[].BLOCK1' jqtest
jq: error (at jqtest:36): Cannot index array with string "BLOCK1"
(^)#(^)#(^)#(^)bminter#ubuntu:~$ jq '.[].BLOCK-2' jqtest
jq: error (at jqtest:36): Cannot index array with string "BLOCK"
(^)#(^)#(^)#(^)bminter#ubuntu:~$ jq '.[].BLOCK-A' jqtest
jq: error: A/0 is not defined at <top-level>, line 1:
.[].BLOCK-A
jq: 1 compile error
(^)#(^)#(^)#(^)bminter#ubuntu:~$
How do I access the array?
The array of objects with non-uniform keys is making things a little tricky here. Once you've gotten past .files you need to start using Array Iteration [] to access those elements and then use object operations like keys to go deeper.
Here is a function which may help in this situation. It scans .files for an object with a key matching the specified key and then returns the corresponding value:
def getfile($k): .files[] | select(keys[] | .==$k) | .[$k];
If jqtest contains the sample data the command
$ jq -M '
def getfile($k): .files[] | select(keys[] | .==$k) | .[$k];
getfile("BLOCK1").SUBBLOCK1.akey1
' jqtest
Returns
"avalue1"
Another approach is to use a function to convert .files[] into a more useful form. e.g.
$ jq -M '
def files: reduce .files[] as $f ({}; ($f|keys[0]) as $k | .[$k] = $f[$k]) ;
files
' jqtest
this returns a more uniform structure without arrays
{
"BLOCK1": {
"SUBBLOCK1": {
"akey1": "avalue1",
"bkey1": "bvalue1",
"ckey1": "cvalue1"
},
"dkey1": "dvalue1",
"key": "evalue1"
},
"BLOCK-2": ...
so with it you can write
files.BLOCK1.SUBBLOCK1
to obtain
{
"akey1": "avalue1",
"bkey1": "bvalue1",
"ckey1": "cvalue1"
}
Note that jq will re-evaluate the files function with each use so the following form may be more practical:
files as $files
| $files.BLOCK1.SUBBLOCK1
If you find this representation useful you may want to skip the function and instead just start your filter with
.files = reduce .files[] as $f ({}; ($f|keys[0]) as $k | .[$k] = $f[$k])
e.g.
$ jq -M '
.files = reduce .files[] as $f ({}; ($f|keys[0]) as $k | .[$k] = $f[$k])
# more stuff goes here
' jqtest
which converts your input to
{
"files": {
"BLOCK1": {
"SUBBLOCK1": {
"akey1": "avalue1",
"bkey1": "bvalue1",
"ckey1": "cvalue1"
},
"dkey1": "dvalue1",
"key": "evalue1"
},
"BLOCK-2": {
"SUBBLOCK2": {
"akey2": "avalue2",
"bkey2": "bvalue2"
},
"ckey2": "cvalue2",
"key": "dvalue2"
},
"BLOCK-A": {
"SUBBLOCK2": {
"akey2": "avalue2",
"bkey2": "bvalue2"
},
"ckey2": "cvalue2",
"key": "dvalue2"
}
},
"NOBLOCK": "value",
"key": "NOBLOCKvalue"
}
making whatever else you need to do after that easier