简体   繁体   中英

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM