Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using jq to produce one line of output per array element in a json object that also includes other fields from the json object

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
like image 420
JoshMc Avatar asked Jan 21 '26 09:01

JoshMc


1 Answers

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

like image 183
peak Avatar answered Jan 22 '26 21:01

peak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!