使用 jq 对象和数组组合 json 个文件

Combining json files using jq objects with array

我试过使用

jq "reduce inputs.skins as $s (.; .skins += $s)" file1.json file2.json > combined.json

但它只是从每个文件

创建了两个boots.name和fun.name

有什么方法可以使用 jq 并组合对象和数组而不会重复?

对于任何混淆,我深表歉意,jq有点复杂,要找到一个简单的教程让我理解

file1.json

{
  "skins": [
    {
      "Item Shortname": "boots.name",
      "skins": [
        2,
        25,
        41,
      ]
    },
    {
      "Item Shortname": "fun.name",
      "skins": [
        12,
        8,
      ]
    }
   ]
}

file2.json

{
  "skins": [
    {
      "Item Shortname": "boots.name",
      "skins": [
        2,
        20,

      ]
    },
    {
      "Item Shortname": "fun.name",
      "skins": [
        90,
        6,
        82,
      ]
    }
   ]
}

combined.json

{
  "skins": [
    {
      "Item Shortname": "boots.name",
      "skins": [
        2,
        20,
        25,
        41,
      ]
    },
    {
      "Item Shortname": "fun.name",
      "skins": [
        90,
        6,
        82,
        12,
        8,
      ]
    }
   ]
}

这里棘手的部分是满足明显的唯一性要求,为此可以使用以下通用过滤器:

# emit a stream of the distinct items in `stream`
def uniques(stream):
 foreach stream as $s ({};
   ($s|type) as $t
   | (if $t == "string" then $s else ($s|tostring) end) as $y
   | if .[$t][$y] then .emit = false else .emit = true | (.item = $s) | (.[$t][$y] = true) end;
   if .emit then .item else empty end );

这样可以确保保留顺序。这有点棘手,因为它是完全通用的——它允许 1"1" 并区分它们,就像 unique 所做的那样。

(如果顺序无关紧要,则可以使用 unique。)

因此,假设按照

行进行调用
jq -s -f program.jq file1.json file2.json

你可以在 program.jq 中放置上面的 def 和下面的“主”程序:

  .[0] as $file1 | .[1] as $file2
  | (INDEX($file1.skins[]; .["Item Shortname"]) | map_values(.skins)) as $dict

  | $file2
  | .skins |= map( .["Item Shortname"] as $name
                   | .skins += $dict[$name]
                   | .skins |= [uniques(.[])] )

更好的解决方案是避免使用 -s 选项(例如如下所示),但上述将两个文件提供给 jq 的方法至少是直接的,并且无论您使用的是哪个版本的 jq 都可以使用。

解决方案使用input

避免吞噬这两个文件的一种方法是将 input 与 -n 命令行选项而不是 -s 结合使用。 jq 程序的“主要”部分如下所示:

(INDEX(input.skins[]; .["Item Shortname"]) | map_values(.skins)) as $dict
| input
| .skins |= map( .["Item Shortname"] as $name
                 | .skins += $dict[$name]
                 | .skins |= [uniques(.[])] )