【问题标题】:Combining json files using jq objects with array使用带有数组的 jq 对象组合 json 文件
【发布时间】:2021-05-16 11:57:43
【问题描述】:

我试过了

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,
      ]
    }
   ]
}

【问题讨论】:

    标签: json jq array-merge filemerge


    【解决方案1】:

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

    # 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,然后是下面的“main”程序:

      .[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(.[])] )
    

    【讨论】:

    • 哇,谢谢!由于我的文件设置,我找不到与我的情况类似的解决方案。感谢您的帮助!
    • 如果另一个文件中缺少一个项目短名称,是否可以添加一项功能?目前,它要求两者具有相同的项目短名称才能合并,否则它们会被丢弃。
    • 这很容易,但具体取决于您的要求。您可能想尝试使用中缀运算符//。
    猜你喜欢
    • 1970-01-01
    • 2019-03-24
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多