如何合并多个 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
  }
}

Demo


也可以通过在开头使用变量来将除法转换为加法:

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*

Demo