jq-根据现有值定期将计算值添加到.json文件中

jq-根据现有值定期将计算值添加到.json文件中,json,jq,Json,Jq,有一个输入文件,其中包含连接到某一特定日期的多个对象。现在是十月四日。但是,每个对象都表示一天中的另一个时间,具有不同的值。文件中的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

有一个输入文件,其中包含连接到某一特定日期的多个对象。现在是十月四日。但是,每个对象都表示一天中的另一个时间,具有不同的值。文件中的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

结果应添加到“consolidated.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
  }
]
我知道我可以用

[.[]|.VALUE_ONE]|add

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

这里有一个解决方案:

#!/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
  }
]
次日将这些值应用于consolidate.json的最新条目 返回第二天的值。例如

{
  "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不一致 数值不同

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

| if .DATE == $date then empty else . end
阻止它添加新日期的数据(如果该日期已存在)。如果有其他保障措施,这是不必要的

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

下一天将生成两个条目:

{
  "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
}

这是一个简单的解决方案,为了便于阐述,它使以下假设易于处理:

input.json的内容如广告所示,尤其是input.json中的对象日期尚未出现在consolidated.json中; consolidated.json中数组中的最后一个条目具有最近的日期,并且该日期早于input.json中条目的日期 合并.jq 调用 如果您确信这样做是安全的,那么您可以添加:| spineconsolidated.json

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

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

不清楚如何计算总共164个值?看起来你在试图建立每天每个值的累积总和。你是如何确定起始金额的?它只是定义为VALUE_ONE[0]=800,还是仅仅来自于以前的调用?jq可以单独做这个计算。。。如果它是从0开始的。如果您能澄清一些细节,这将非常有帮助。数值键之间的具体计算是否固定?某些input.json是否可以引入以前未看到的新值?是在input.json中使用VALUE_TWO和VALUE_TWO。。。在consolidated.json中是故意的还是错误的?也就是说,为什么价值二和价值三。。。当一个键的值显示为非时,键相关?如果在数据的订购和可能的意外再处理方面需要采取任何预防措施,该怎么办?
{
  "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
}
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
{
  "DATE": "04.10.2017",
  "VALUE_ONE_TODAY": 70,
  "VALUE_ONE_TOTAL": 960,
  "VALUE_THREE_TODAY": 10,
  "VALUE_THREE_TOTAL": 164
}