如何使用jq合并2 json文件?

Jan*_*nfy 106 shell command-line json jq

我在shell脚本中使用jq工具(jq-json-processor)来解析json.

我有2个json文件,想要将它们合并为一个唯一的文件

这里是文件的内容:

文件1

{
    "value1": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2"
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

文件2

{
    "status": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value3": "v3"
        },      
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

预期结果

{
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        },
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试了很多组合,但我得到的唯一结果是以下,这不是预期的结果:

{
  "ccc": {
    "value2": "v2",
    "value1": "v1"
  },
  "bbb": {
    "value2": "v2",
    "value1": "v1"
  },
  "aaa": {
    "value2": "v2",
    "value1": "v1"
  }
}
{
  "ddd": {
    "value4": 4,
    "value3": "v3"
  },
  "bbb": {
    "value3": "v3"
  },
  "aaa": {
    "value4": 4,
    "value3": "v3"
  }
}
Run Code Online (Sandbox Code Playgroud)

使用此命令:

jq -s '.[].value' file1 file2
Run Code Online (Sandbox Code Playgroud)

Sim*_*nen 121

从1.4开始,现在可以与*操作员一起使用.给定两个对象时,它将以递归方式合并它们.例如,

jq -s '.[0] * .[1]' file1 file2
Run Code Online (Sandbox Code Playgroud)

会得到你:

{
  "value1": 200,
  "timestamp": 1382461861,
  "value": {
    "aaa": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3",
      "value4": 4
    },
    "bbb": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3"
    },
    "ccc": {
      "value1": "v1",
      "value2": "v2"
    },
    "ddd": {
      "value3": "v3",
      "value4": 4
    }
  },
  "status": 200
}
Run Code Online (Sandbox Code Playgroud)

如果你还想摆脱其他键(比如你的预期结果),一种方法是:

jq -s '.[0] * .[1] | {value: .value}' file1 file2
Run Code Online (Sandbox Code Playgroud)

或者可能更有效(因为它不合并任何其他值):

jq -s '.[0].value * .[1].value | {value: .}' file1 file2
Run Code Online (Sandbox Code Playgroud)

  • _注意_:`-s` 标志很重要,因为没有它两个对象不在数组中。 (2认同)

小智 55

用途jq -s add:

$ echo '{"a":"foo","b":"bar"} {"c":"baz","a":0}' | jq -s add
{
  "a": 0,
  "b": "bar",
  "c": "baz"
}
Run Code Online (Sandbox Code Playgroud)

这将从stdin读取所有JSON文本到一个数组(jq -s这样做)然后它"减少"它们.

(add定义为def add: reduce .[] as $x (null; . + $x);,迭代输入数组的/对象的值并添加它们.对象添加==合并.)

  • 是否可以使用这种方法进行递归合并(*运算符)? (4认同)
  • @DaveFoster 是的,像 `reduce .[] as $x ({}; . * $x)` – 另见 [jrib's answer](http://stackoverflow.com/a/36218044/1797912)。 (2认同)

Fil*_*ile 29

谁知道你是否仍然需要它,但这是解决方案.

一旦你--slurp选择了,这很容易!

--slurp/-s:
    Instead of running the filter for each JSON object in the input,
    read the entire input stream into a large array and run the filter just once.
Run Code Online (Sandbox Code Playgroud)

然后+操作员会做你想做的事:

jq -s '.[0] + .[1]' config.json config-user.json
Run Code Online (Sandbox Code Playgroud)

(注意:如果要合并内部对象而不是仅使用正确的文件覆盖左侧文件,则需要手动执行)


pmf*_*pmf 24

到目前为止,没有给出任何解决方案或评论考虑使用input访问第二个文件。使用它将不需要构建额外的结构来提取,例如使用--slurp(或-s) 选项时的全包数组,这在几乎所有其他方法中都有。

要合并顶层的两个文件,只需使用以下命令将第二个文件添加input到第一个文件:.+

jq '. + input' file1.json file2.json
Run Code Online (Sandbox Code Playgroud)

要在所有级别上递归合并两个文件,请使用*as 运算符执行相同操作:

jq '. * input' file1.json file2.json
Run Code Online (Sandbox Code Playgroud)

也就是说,要递归合并两个文件,将两个对象缩减为其value字段,请首先使用以下方法过滤它们{value}

jq '{value} * (input | {value})' file1.json file2.json
Run Code Online (Sandbox Code Playgroud)
{
  "value": {
    "aaa": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3",
      "value4": 4
    },
    "bbb": {
      "value1": "v1",
      "value2": "v2",
      "value3": "v3"
    },
    "ccc": {
      "value1": "v1",
      "value2": "v2"
    },
    "ddd": {
      "value3": "v3",
      "value4": 4
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

演示

请注意,仅在合并. * input | {value}减少的解决方案(如将),代码较短,但会再次“构建额外的结构以从中提取”徒劳,如果最终切断的部分变大,这可能会产生大量开销。

为了操作两个以上的文件,要么相应地使用input多次,要么以编程方式迭代所有文件inputs,如

jq 'reduce inputs as $i (.; . * $i)' file*.json
Run Code Online (Sandbox Code Playgroud)

请注意,在任何一种情况下,第一个文件始终通过输入上下文访问.,而input(s)仅寻址其余文件,即从第二个文件开始(当然,除非给出--null-inputor选项)。-n


jri*_*rib 16

这是一个*在任意数量的对象上递归(使用)的版本:

echo '{"A": {"a": 1}}' '{"A": {"b": 2}}' '{"B": 3}' | jq --slurp 'reduce .[] as $item ({}; . * $item)'
{
  "A": {
    "a": 1,
    "b": 2
  },
  "B": 3
}
Run Code Online (Sandbox Code Playgroud)

  • 好答案。合并目录中的所有文件时效果很好:`jq -s'reduce。[] as $ item({};。* $ item)'* .json` (2认同)

pea*_*eak 7

首先,{“ value”:.value}可以缩写为{value}。

其次,-argfile选项(在jq 1.4和jq 1.5中可用)可能会引起人们的兴趣,因为它避免了使用--slurp选项。

将它们放在一起,可以按指定的方式组合两个文件中的两个对象,如下所示:

$ jq -n --argfile o1 file1 --argfile o2 file2 '$o1 * $o2 | {value}'
Run Code Online (Sandbox Code Playgroud)

因为输入来自--argfile选项,所以-n标志告诉jq不要从stdin读取。

  • jq已将`--argile`弃用为`--slurpfile` (2认同)

小智 5

这可用于合并命令中指定的任意数量的文件:

jq -rs 'reduce .[] as $item ({}; . * $item)' file1.json file2.json file3.json ... file10.json

或者这适用于任意数量的文件

jq -rs 'reduce .[] as $item ({}; . * $item)' ./*.json


Jon*_*Jon 5

我不想丢弃对象中以前的非唯一键

\n
jq -n '{a:1, c:2}, {b:3, d:4}, {a:5,d:6}' |\njq -s 'map(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)|add})|add'\n{\n  "a": 6,\n  "b": 3,\n  "c": 2,\n  "d": 10\n}\n
Run Code Online (Sandbox Code Playgroud)\n

或者,如果您只想保留值的数组,请在提取值后删除添加map(.value)|\xcc\xb6a\xcc\xb6d\xcc\xb6d\xcc\xb6

\n
jq -n '{a:1, c:2}, {b:3, d:4}, {a:5,d:6}' |\njq -s 'map(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)})|add'\n{\n  "a": [1, 5],\n  "b": [3],\n  "c": [2],\n  "d": [4, 6]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

尝试删除命令的每个部分并查看每个步骤如何修改对象数组...也就是运行这些步骤并查看输出如何变化

\n
map(to_entries)\nmap(to_entries)|flatten\nmap(to_entries)|flatten|group_by(.key)\nmap(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)})\nmap(to_entries)|flatten|group_by(.key)|map({(.[0].key):map(.value)})|add\n
Run Code Online (Sandbox Code Playgroud)\n