jq:将数组中的值与常量相乘,并将结果添加到另一个文件中具有匹配id的对象

时间:2017-09-21 13:01:18

标签: json bash jq

因此我的目录中有三个.json文件。我已经动态创建了第一个文件(使用linux bash和jq),其中包含一个对象,包括数组“RATIO”:

  • ratio.json:

    [
     {...,"RATIO":[0.5,0.7,0.8,0.9], ....}
    ]
    

在第二个文件中我存储了常量(这只是硬编码所以常量也可以直接移动到代码中,如果这更容易):

  • constants.json:

    [
     {"ID":"aaa","CONST":250},
     {"ID":"bbb","CONST":350},
     {"ID":"ccc","CONST":200},
     {"ID":"ddd","CONST":190}
    ]
    

第三个文件是应该发生“神奇”的地方:

  • data.json:

    [
     {"ID":"aaa","time_CET":"00:00:00"},
     {"ID":"aaa","time_CET":"00:15:00"},
     {"ID":"aaa","time_CET":"00:30:00"},
     {"ID":"aaa","time_CET":"00:45:00"},
    
     {"ID":"bbb","time_CET":"00:00:00"},
     {"ID":"bbb","time_CET":"00:15:00"},
     {"ID":"bbb","time_CET":"00:30:00"},
     {"ID":"bbb","time_CET":"00:45:00"},
    
     {"ID":"ccc","time_CET":"00:00:00"},
     {"ID":"ccc","time_CET":"00:15:00"},
     {"ID":"ccc","time_CET":"00:30:00"},
     {"ID":"ccc","time_CET":"00:45:00"},
    
     {"ID":"ddd","time_CET":"00:00:00"},
     {"ID":"ddd","time_CET":"00:15:00"},
     {"ID":"ddd","time_CET":"00:30:00"},
     {"ID":"ddd","time_CET":"00:45:00"}
    ]
    

    此数组中的所有对象都应该通过元素“VAL”进行扩展,该元素是通过将RATIO与CONST相乘来计算的。所以在我的情况下,RATIO [0](即0.5)用于time_CET =“00:00:00”的每个对象。 RATIO [1]用于time_CET = 00:15:00等,依此类推。 data.json中的数组已经按照您所看到的排序(00:00:00总是每个ID的第一个),这就是为什么我认为数组索引的技巧应该有效。 所以最后,data.json文件看起来应该是这样的(右边是VAL的计算逻辑):

  • data.json:

    [     
    
      {"ID":"aaa","time_CET":"00:00:00", "VAL": 125}, ->0.5*250
      {"ID":"aaa","time_CET":"00:15:00", "VAL": 175}, ->0.7*250
      {"ID":"aaa","time_CET":"00:30:00", "VAL": 200}, ->0.8*250
      {"ID":"aaa","time_CET":"00:45:00", "VAL": 225}, ->0.9*250
    
      {"ID":"bbb","time_CET":"00:00:00", "VAL": 175}, ->0.5*350
      {"ID":"bbb","time_CET":"00:15:00", "VAL": 245}, ->0.7*350
      {"ID":"bbb","time_CET":"00:30:00", "VAL": 280}, ->0.8*350
      {"ID":"bbb","time_CET":"00:45:00", "VAL": 315}, ->0.9*350
    
      {"ID":"ccc","time_CET":"00:00:00", "VAL": 100}, ->0.5*200
      {"ID":"ccc","time_CET":"00:15:00", "VAL": 140}, ->0.7*200
      {"ID":"ccc","time_CET":"00:30:00", "VAL": 160}, ->0.8*200
      {"ID":"ccc","time_CET":"00:45:00", "VAL": 180}, ->0.9*200
    
      {"ID":"ddd","time_CET":"00:00:00", "VAL": 95}, ->0.5*190
      {"ID":"ddd","time_CET":"00:15:00", "VAL": 133}, ->0.7*190
      {"ID":"ddd","time_CET":"00:30:00", "VAL": 152}, ->0.8*190
      {"ID":"ddd","time_CET":"00:45:00", "VAL": 171}, ->0.9*190
    ]
    

所以我不确定这是否可行。也许我必须将比率数组重塑为对象? (具有“time_cet”键且不是值数组的对象)。

无论如何,使用jq(也许是linux bash)实现这一目标的最佳方法是什么?谢谢!

更新:两种解决方案现在都有效,非常感谢。 这可能是另一个主题,但我想添加一个错误处理程序来捕获异常,特别是对于RATIO数组。 可能会发生这个数组

1.不包含指定索引/未定义的值

2.Value不是整数

无论如何我想为VAL设置一个默认值。错误消息应该记录在另一个文件中,如果可能的话..(我可以在这里使用当前日期吗? - >也许可以发送到STDERR?)Thx。

2 个答案:

答案 0 :(得分:0)

假设以下jq程序在一个文件中,比如program.jq,那么调用:

jq --argfile ratio ratio.json --argfile constants constants.json  -f program.jq data.json

产生所需的结果,至少在使用jq 1.5或更高版本时:

# r should be an array of ratios
# input is assumed to be an object with .time_CET
def getRatio(r):
  if .time_CET=="00:00:00" then r[0]
  elif  .time_CET=="00:15:00" then r[1]
  elif  .time_CET=="00:30:00" then r[2]
  else r[3]
  end
  ;

def todict: reduce .[] as $o ({}; . + ($o | { (.ID): .CONST }));

def extend(r):
  ($constants|todict)[.ID]  as $c
  | .VAL = getRatio(r) * $c
  ;

($ratio[0] | .RATIO) as $RATIO
| map(extend($RATIO))

答案 1 :(得分:0)

这是一个解决方案:

# recent versions of jq include this in builtin.jq.
# we redefine it here in case it's not present
def INDEX(stream; idx_expr):
  reduce stream as $row (
    {}
  ; .[$row|idx_expr|if type != "string" then tojson else . end] |= $row
  )
;

# make an array of all the times that appear in time_CET
def datatimes:
   [$data[].time_CET] | unique[]
;

# make an object mapping time_CET to ratios
def time_to_ratio:
    reduce datatimes as $i (
      {}
    ; .[$i] = $ratio[0].RATIO[length]
    )
;

# main procedure here

  INDEX($constants[];.ID) as $ctable
| time_to_ratio as $rtable
| $data
| map(.VAL = $ctable[.ID].CONST * $rtable[.time_CET])

如果此过滤器位于filter.jq且其他数据分别位于constants.jsonratio.jsondata.json文件中,则命令

jq -Mnc \
   --argfile constants constants.json \
   --argfile data data.json \
   --argfile ratio ratio.json \
   -f filter.jq

产生

[
  {
    "ID": "aaa",
    "time_CET": "00:00:00",
    "VAL": 125
  },
  {
    "ID": "aaa",
    "time_CET": "00:15:00",
    "VAL": 175
  },
  {
    "ID": "aaa",
    "time_CET": "00:30:00",
    "VAL": 200
  },
  {
    "ID": "aaa",
    "time_CET": "00:45:00",
    "VAL": 225
  },
  {
    "ID": "bbb",
    "time_CET": "00:00:00",
    "VAL": 175
  },
  {
    "ID": "bbb",
    "time_CET": "00:15:00",
    "VAL": 244.99999999999997
  },
  {
    "ID": "bbb",
    "time_CET": "00:30:00",
    "VAL": 280
  },
  {
    "ID": "bbb",
    "time_CET": "00:45:00",
    "VAL": 315
  },
  {
    "ID": "ccc",
    "time_CET": "00:00:00",
    "VAL": 100
  },
  {
    "ID": "ccc",
    "time_CET": "00:15:00",
    "VAL": 140
  },
  {
    "ID": "ccc",
    "time_CET": "00:30:00",
    "VAL": 160
  },
  {
    "ID": "ccc",
    "time_CET": "00:45:00",
    "VAL": 180
  },
  {
    "ID": "ddd",
    "time_CET": "00:00:00",
    "VAL": 95
  },
  {
    "ID": "ddd",
    "time_CET": "00:15:00",
    "VAL": 133
  },
  {
    "ID": "ddd",
    "time_CET": "00:30:00",
    "VAL": 152
  },
  {
    "ID": "ddd",
    "time_CET": "00:45:00",
    "VAL": 171
  }
]