简体   繁体   中英

jq: reduce json arrays with a Math function

I wrote this JSONProcessor bash function to sum, average, get min and get max values from arrays based on the name values. The average and min results are not correct and I can't for the life of me figure out what I am doing wrong.

function JSONProccessor {
 jq '
  def myMathFunc:
    if (.name | test("^sum", "")) then
      {"\(.name)": (.values | add)}                           
    elif (.name | test("^avg|^global-avg", "")) then
      {"\(.name)": ((.values | add) / (.values | length)) }   
    elif (.name | test("^max", "")) then
      {"\(.name)": (.values | max) }   
    elif (.name | test("^min", "")) then
      {"\(.name)": (.values | min) } 
    else
      {"\(.name)": .values[]}                              
    end;

   [
  .Response.stats.data[] |
  .identifier.names[] as $name |
  .identifier.values[] as $val |
  {"\($name)": "\($val)"} + ([
    .metric[] | myMathFunc
  ] | add)
]
'  < ${1} > ${2}
}

Input JSON

{
  "Response" : {
    "TimeUnit" : [ 1588153140000, 1588153200000 ],
    "metaData" : {
      "errors" : [ ]
    },
    "resultTruncated" : false,
    "stats" : {
      "data" : [ {
        "identifier" : {
          "names" : [ "apiproxy" ],
          "values" : [ "authn" ]
        },
        "metric" : [ {
          "env" : "prod",
          "name" : "min(request_processing_latency)",
          "values" : [ 917.0, 6.0 ]
        }, {
          "env" : "prod",
          "name" : "avg(total_response_time)",
          "values" : [ 2203.5, 13.0 ]
        }, {
          "env" : "prod",
          "name" : "max(request_processing_latency)",
          "values" : [ 1286.0, 6.0 ]
        }, {
          "env" : "prod",
          "name" : "global-avg-total_response_time",
          "values" : [ 1473.3333333333333 ]
        }, {
          "env" : "prod",
          "name" : "sum(message_count)",
          "values" : [ 2.0, 1.0 ]

        } 
        ]
      }
     ]
    }
  }
}

Output

[
  {
    "apiproxy": "authn",
    "min(request_processing_latency)": 923,
    "avg(total_response_time)": 2216.5,
    "max(request_processing_latency)": 1292,
    "global-avg-total_response_time": 1473.3333333333333,
    "sum(message_count)": 3
  }
]

Can you please review and let me know if I am missing anything obvious?

Your idea is right, but the test() function does not "need" the 2nd argument "" as you have defined. You just need the test() function to return a bool to assert your match. Removing the 2nd argument should make your function work as expected.

The test() function supports prototypes test(REGEX; FLAGS) where FLAGS defined in don't matter your logic at all. The test() function does not even take arguments separated by , but only by ; de-limiter.

jq-play snippet

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