有一个输入文件,其中包含连接到特定日期的多个对象。 (在这种情况下,它是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
但我不知道如何将其纳入所需的结构并使用最后一天的总数。 谢谢!
答案 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
}
答案 1 :(得分:0)
这是一个简单易懂的解决方案,为简化说明而做出以下(易于解决)假设:
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
}