jq-定期将基于现有值的计算值添加到.json文件中

时间:2017-10-29 15:52:34

标签: json jq

有一个输入文件,其中包含连接到特定日期的多个对象。 (在这种情况下,它是10月4日)。但是,每个对象代表当天的另一个时间,具有不同的值。 " ID"和文件中的日期始终相同:

INPUT.json:

[
  {
    "DATE": "04.10.2017 10:20",
    "ID":"x",
    "VALUE_ONE": 20,
    "VALUE_TWO": 3
  },
  {
    "DATE": "04.10.2017 12:50",
    "ID":"x",
    "VALUE_ONE": 40,
    "VALUE_TWO": 5
  },
  {
    "DATE": "04.10.2017 14:20",
    "ID":"x",
    "VALUE_ONE": 10,
    "VALUE_TWO": 2
  }   
]

我现在要做的是计算当天的总价值并做一些数学计算。 (在这种情况下,加3或乘3)。

结果应添加到“merge.json”中。文件,每天应包含一个对象。为确保这一点,这个过程将每天重复。

我评论了' //'背后的计算步骤。 :

CONSOLIDATED.json:

[
  {
    "DATE": "02.10.2017",
    "VALUE_ONE_TODAY": 40,
    "VALUE_ONE_TOTAL": 800,
    "VALUE_THREE_TODAY": 5,
    "VALUE_THREE_TOTAL": 110
  },
  {
    "DATE": "03.10.2017",
    "VALUE_ONE_TODAY": 90,
    "VALUE_ONE_TOTAL": 890, // =800+90
    "VALUE_THREE_TODAY": 8,
    "VALUE_THREE_TOTAL": 134 // = 110 + 3*8
  },
  {           //this object is new!
    "DATE": "04.10.2017",
    "VALUE_ONE_TODAY": 70,
    "VALUE_ONE_TOTAL": 960, // =890+70
    "VALUE_THREE_TODAY": 10,
    "VALUE_THREE_TOTAL": 164 // =134 +3*10
  }
]

我知道我可以用

获得INPUT.json的总数
[.[]|.VALUE_ONE]|add

[.[]|.VALUE_TWO*3]|add

但我不知道如何将其纳入所需的结构并使用最后一天的总数。 谢谢!

2 个答案:

答案 0 :(得分:0)

这是一个解决方案:

#!/bin/bash

jq -M --argfile i input.json '

    def VALUE_keys: keys[] | select(startswith("VALUE"));
    def TODAY_keys: keys[] | select(endswith("TODAY"));
    def TODAY_($k): "\($k)_TODAY";
    def TOTAL_($k): "\($k)_TOTAL";

    def new_totals: 
        $i
      | (map(VALUE_keys)|unique) as $attrs
      | reduce (.[]|.DATE |= .[:10]) as $d ({}
        ; reduce $attrs[] as $a (.
          ; [$d.DATE, $a] as $p | setpath($p; getpath($p)+$d[$a])
          )
        )
      | keys[] as $date 
      | [$date, .[$date]] ;

    def aggregate($k; $total):
        .[TODAY_($k)] = $total
      | if $k == "VALUE_THREE" 
        then .[TOTAL_($k)] += $total * 3
        else .[TOTAL_($k)] += $total
        end ;

    def next_day:
        foreach new_totals as [$date, $totals] (
           max_by(.DATE) 
         ; if .DATE == $date then empty else . end
         | .DATE = $date
         | .[TODAY_keys] = 0 
         | reduce ($totals|keys[]) as $k (.; aggregate($k; $totals[$k]))
       )
    ;

    . + [next_day]


' consolidated.json | sponge consolidated.json

new_totals计算返回日期和值数组的input.json总和。从它产生的样本数据:

[
  "04.10.2017",
  {
    "VALUE_ONE": 70,
    "VALUE_TWO": 10
  }
]

next_day将这些值应用于consolidated.json的最新条目 返回第二天的值。 E.g。

{
  "DATE": "04.10.2017",
  "VALUE_ONE_TODAY": 70,
  "VALUE_ONE_TOTAL": 960,
  "VALUE_THREE_TODAY": 0,
  "VALUE_THREE_TOTAL": 134,
  "VALUE_TWO_TODAY": 10,
  "VALUE_TWO_TOTAL": 10
}

请注意,示例输出与示例input.json不一致 价值观不同。

脚本将此内容添加到输入中,并使用sponge更新consolidated.json新数据。注意该行

| if .DATE == $date then empty else . end
如果该日已经存在,

会阻止它添加新日期的数据。如果有其他保护措施,这是不必要的。

另请注意,next_day使用foreach来处理input.json包含数据超过一天的情况。例如,如果input.json的第一个元素是

{
   "DATE": "03.12.2017 10:20",
   "ID":"x",
   "VALUE_ONE": 20,
   "VALUE_TWO": 3
}

next_day会生成两个条目:

{
  "DATE": "03.12.2017",
  "VALUE_ONE_TODAY": 20,
  "VALUE_ONE_TOTAL": 910,
  "VALUE_THREE_TODAY": 0,
  "VALUE_THREE_TOTAL": 134,
  "VALUE_TWO_TODAY": 3,
  "VALUE_TWO_TOTAL": 3
}
{
  "DATE": "04.10.2017",
  "VALUE_ONE_TODAY": 50,
  "VALUE_ONE_TOTAL": 960,
  "VALUE_THREE_TODAY": 0,
  "VALUE_THREE_TOTAL": 134,
  "VALUE_TWO_TODAY": 7,
  "VALUE_TWO_TOTAL": 10
}

Try it online!

答案 1 :(得分:0)

这是一个简单易懂的解决方案,为简化说明而做出以下(易于解决)假设:

  • input.json的内容与广告一样,特别是input.json中的对象日期尚未出现在consolidated.json中;
  • consolidated.json中数组中的最后一个条目具有最新日期,并且它早于input.json中的条目日期

consolidate.jq

def aggregate:
  {DATE: (.[0]|.DATE|split(" ")[0]),
   VALUE_ONE_TODAY: (map(.VALUE_ONE) | add),
   VALUE_TWO_TODAY: (map(.VALUE_TWO) | add)}
  ;

.[-1] as $previous
| ($i | aggregate
   | {DATE,
      VALUE_ONE_TODAY,
      VALUE_ONE_TOTAL : ($previous.VALUE_ONE_TOTAL + .VALUE_ONE_TODAY),
      VALUE_THREE_TODAY : ($previous.VALUE_TWO_TOTAL + .VALUE_TWO_TODAY) }
   |  .VALUE_THREE_TOTAL = ($previous.VALUE_THREE_TOTAL + 3 * .VALUE_THREE_TODAY) ) as $today
| . + [$today]

调用

jq -f consolidate.jq --argfile i input.json consolidated.json

如果您确定这样做是安全的,您可以坚持:| sponge consolidated.json

输出

添加的条目符合要求,即:

{
  "DATE": "04.10.2017",
  "VALUE_ONE_TODAY": 70,
  "VALUE_ONE_TOTAL": 960,
  "VALUE_THREE_TODAY": 10,
  "VALUE_THREE_TOTAL": 164
}