如何合并多个 JSON 个文件和平均值
How to merge multiple JSON files and average values
我尝试合并不同的 JSON 文件,其中包含这种数据:
#file1:
{
"user1": {
"server1": 7.2,
"server2": 10.3
},
"user2": {
"server1": 15
}
}
#file2:
{
"user1": {
"server1": 8.5,
"server3": 20.5
},
"user3": {
"server1": 28
}
}
以此类推(每小时 12 次)。
这些数据是包含服务器使用百分比的用户列表,每 5 分钟更新一次(用户可能会消失并重新出现,具体取决于资源使用情况)。
我在 Linux 下,我使用不同的 Shell 工具生成这些文件,例如 jq
.
我的目标是每小时获取一个合并文件,所有可用数据的平均负载,就像这样(只考虑上面的 2 个文件):
#result:
{
"user1": {
"server1": 7.85,
"server2": 5.15,
"server3": 10.25
},
"user2": {
"server1": 7.5
},
"user3": {
"server1": 14
}
}
我尝试使用 reduce
命令进行多次查询,但没有任何效果。
也许最好的方法应该是解析每个文件,提取数据并将用户存储在不同的文件中,然后合并所有数据?
感谢您的分析和示例。
一种方法:
jq -n \
--argjson d1 file1.json \
--argjson d2 file2.json \
'
$d1 * $d2 |
with_entries(
.key as $user |
.value = (
with_entries(
.key as $server |
.value | ( $d1[ $user ][ $server ] + $d2[ $user ][ $server ] ) / 2
)
)
)
'
Demo 在 jqplay
$d1 * $d2
创建了正确的结构,但具有错误的值。然后我们修正这些值。
另一种方法:
jq -s '
length as $n |
reduce ( .[] | to_entries[] ) as $_ ( { };
$_.key as $user |
reduce ( $_.value | to_entries[] ) as $_ ( .;
$_.key as $server |
.[ $user ][ $server ] += $_.value / $n
)
)
' file1.json file2.json
Demo 在 jqplay
这个可以处理两个以上的文件!
这是一个针对任意数量的输入文件的解决方案。它首先将每个值除以输入文件的数量,然后将它们全部加起来并保留键:
jq -s '
.[][][] /= length
| reduce (.[] | to_entries[]) as $u ({};
reduce ($u.value | to_entries[]) as $s (.;
.[$u.key][$s.key] += $s.value
)
)
' file*
{
"user1": {
"server1": 7.85,
"server2": 5.15,
"server3": 10.25
},
"user2": {
"server1": 7.5
},
"user3": {
"server1": 14
}
}
也可以通过在开头使用变量来将除法转换为加法:
jq -s '
length as $c
| reduce (.[] | to_entries[]) as $u ({};
reduce ($u.value | to_entries[]) as $s (.;
.[$u.key][$s.key] += $s.value / $c
)
)
' file*
我尝试合并不同的 JSON 文件,其中包含这种数据:
#file1:
{
"user1": {
"server1": 7.2,
"server2": 10.3
},
"user2": {
"server1": 15
}
}
#file2:
{
"user1": {
"server1": 8.5,
"server3": 20.5
},
"user3": {
"server1": 28
}
}
以此类推(每小时 12 次)。
这些数据是包含服务器使用百分比的用户列表,每 5 分钟更新一次(用户可能会消失并重新出现,具体取决于资源使用情况)。
我在 Linux 下,我使用不同的 Shell 工具生成这些文件,例如 jq
.
我的目标是每小时获取一个合并文件,所有可用数据的平均负载,就像这样(只考虑上面的 2 个文件):
#result:
{
"user1": {
"server1": 7.85,
"server2": 5.15,
"server3": 10.25
},
"user2": {
"server1": 7.5
},
"user3": {
"server1": 14
}
}
我尝试使用 reduce
命令进行多次查询,但没有任何效果。
也许最好的方法应该是解析每个文件,提取数据并将用户存储在不同的文件中,然后合并所有数据?
感谢您的分析和示例。
一种方法:
jq -n \
--argjson d1 file1.json \
--argjson d2 file2.json \
'
$d1 * $d2 |
with_entries(
.key as $user |
.value = (
with_entries(
.key as $server |
.value | ( $d1[ $user ][ $server ] + $d2[ $user ][ $server ] ) / 2
)
)
)
'
Demo 在 jqplay
$d1 * $d2
创建了正确的结构,但具有错误的值。然后我们修正这些值。
另一种方法:
jq -s '
length as $n |
reduce ( .[] | to_entries[] ) as $_ ( { };
$_.key as $user |
reduce ( $_.value | to_entries[] ) as $_ ( .;
$_.key as $server |
.[ $user ][ $server ] += $_.value / $n
)
)
' file1.json file2.json
Demo 在 jqplay
这个可以处理两个以上的文件!
这是一个针对任意数量的输入文件的解决方案。它首先将每个值除以输入文件的数量,然后将它们全部加起来并保留键:
jq -s '
.[][][] /= length
| reduce (.[] | to_entries[]) as $u ({};
reduce ($u.value | to_entries[]) as $s (.;
.[$u.key][$s.key] += $s.value
)
)
' file*
{
"user1": {
"server1": 7.85,
"server2": 5.15,
"server3": 10.25
},
"user2": {
"server1": 7.5
},
"user3": {
"server1": 14
}
}
也可以通过在开头使用变量来将除法转换为加法:
jq -s '
length as $c
| reduce (.[] | to_entries[]) as $u ({};
reduce ($u.value | to_entries[]) as $s (.;
.[$u.key][$s.key] += $s.value / $c
)
)
' file*