jq合并多个json文件合并任意数组元素

jq合并多个json文件合并任意数组元素,json,jq,Json,Jq,我想使用jq合并多个文件,如果多个文件包含一个名称为的数组,我需要合并数组(顺序无关紧要) 比如说 文件1 文件2 建议其他堆栈溢出文章合并这些json,我应该做: jq -s '.[0] * .[1]' file1 file2 但这让我明白: { "value1": 200, "timestamp": 1382461861, "parameter": [ { "param": 2 } ], "status": 200, "value": {

我想使用jq合并多个文件,如果多个文件包含一个名称为的数组,我需要合并数组(顺序无关紧要)

比如说

文件1

文件2

建议其他堆栈溢出文章合并这些json,我应该做:

jq -s '.[0] * .[1]' file1 file2
但这让我明白:

{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    {
      "param": 2
    }
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}
我想要的是:

{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    { "param": 1}, 
    { "param": 2}
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}
请注意,“parameter”数组应该包含file1和file2中的元素

我还需要一个解决方案,它不需要指定数组中的字段,而且数组可以嵌套在json的任何级别

我愿意接受一个不使用jq的解决方案,我想一个小的python脚本就可以了

我找到的最接近的解决方案要求我知道参数是数组

 jq -s '.[0] *  .[1]' file1.json file2.json >temp.json
 jq -s '.[0].parameter=([.[].parameter]|flatten)|.[0]' temp.json file1.json
输出是

{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    {
      "param": 2
    },
    {
      "param": 1
    }
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}

您基本上是在实施自己的合并方案。如果您想要一个通用的解决方案,那么您需要定义一个函数,这样它就可以递归地完成。这与“
*
不同,但具有不同的数组语义”,但您可以使用如下内容:

def new_merge($item):
    if type == ($item|type) then   # if same types
        if type == "array" then        # concatenate the arrays
            . + $item
        elif type == "object" then     # recursively merge objects
            reduce ($item|to_entries[]) as {$key,$value} (.;
                .[$key] |= new_merge($value)
            )
        else                           # just take the "other" value
            $item // .
        end
    else                           # just take the "other" value
        $item // .
    end
    ;
$ jq 'reduce inputs as $i (.; do_merge($i))' file*.json
{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    {
      "param": 1
    },
    {
      "param": 2
    }
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}
我会把它放在你的
~/.jq
文件中,然后像这样调用:

def new_merge($item):
    if type == ($item|type) then   # if same types
        if type == "array" then        # concatenate the arrays
            . + $item
        elif type == "object" then     # recursively merge objects
            reduce ($item|to_entries[]) as {$key,$value} (.;
                .[$key] |= new_merge($value)
            )
        else                           # just take the "other" value
            $item // .
        end
    else                           # just take the "other" value
        $item // .
    end
    ;
$ jq 'reduce inputs as $i (.; do_merge($i))' file*.json
{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    {
      "param": 1
    },
    {
      "param": 2
    }
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}
另一方面,如果您希望像原始问题中那样递归合并数组项,只需将数组大小写更改为递归合并相应的项即可

def new_merge2($item):
    if type == ($item|type) then
        if type == "array" then
            [.,$item] | transpose[] as [$a,$b] | [$a | new_merge2($b)]
        elif type == "object" then
            reduce ($item|to_entries[]) as {$key,$value} (.;
                .[$key] |= new_merge2($value)
            )
        else
            $item // .
        end
    else
        $item // .
    end
    ;
这一版本将产生:

{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    {
      "param1": 1,
      "param2": 2
    }
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}

这里是一个解决问题的方法,在这种情况下,有两个文件,每个文件都有一个对象,其中在某个级别上至少有一个相同的命名数组值字段

许多方面的要求都不明确,因此以下可能需要根据更详细的要求进行调整。如果有两个以上的文件,则可以使用相同的技术,但细节将取决于详细的需求

jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '

  # a and b are expected to be jq paths ending with a string
  # emit the array of the intersection of key names
  def common(a;b):
    ((a|map(.[-1])) + (b|map(.[-1]))) 
    | unique;

  $file1[0] as $f1
  | $file2[0] as $f2
  | [$f1 | paths as $p | select(getpath($p) | type == "array") | $p] as $p1
  | [$f2 | paths as $p | select(getpath($p) | type == "array") | $p] as $p2
  | $f1+$f2
  | if ($p1|length) > 0 and ($p2|length) > 0 
    then common($p1; $p2) as $both
    | if ($both|length) > 0 
      then first( $p1[] | select(.[-1] == $both[0])) as $p1
      |    first( $p2[] | select(.[-1] == $both[0])) as $p2
      | ($f1 | getpath($p1)) as $a1
      | ($f2 | getpath($p2)) as $a2
      | setpath($p1; $a1 + $a2)
      else .
      end
    else .
    end
  '
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '
  $file1[0] as $f1
  | $file2[0] as $f2
  | reduce ($f1 | paths) as $p ($f1+$f2;
      ($f1|getpath($p)) as $v1
      | ($f2|getpath($p)) as $v2
      | if ($v1 | type == "array") and
           ($v2 | type == "array")
        then setpath($p; $v1 + $v2)
        else .
        end)

'
输出 使用给定输入,在第二个文件中添加缺少的“:”后,输出为:

{
  "value1": 200,
  "timestamp": 1382461861,
  "parameter": [
    {
      "param1": 1
    },
    {
      "param2": 2
    }
  ],
  "status": 200,
  "value": {
    "aaa": {
      "value3": "v3",
      "value4": 4
    }
  }
}

对于两个文件(每个文件有一个对象)的情况,下面是一个简单但通用的解决方案

此解决方案将在同一路径上连接每对数组。希望它足够简单,可以为自己说话,并且可以进行修改以处理范围更广、更详细的需求

jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '

  # a and b are expected to be jq paths ending with a string
  # emit the array of the intersection of key names
  def common(a;b):
    ((a|map(.[-1])) + (b|map(.[-1]))) 
    | unique;

  $file1[0] as $f1
  | $file2[0] as $f2
  | [$f1 | paths as $p | select(getpath($p) | type == "array") | $p] as $p1
  | [$f2 | paths as $p | select(getpath($p) | type == "array") | $p] as $p2
  | $f1+$f2
  | if ($p1|length) > 0 and ($p2|length) > 0 
    then common($p1; $p2) as $both
    | if ($both|length) > 0 
      then first( $p1[] | select(.[-1] == $both[0])) as $p1
      |    first( $p2[] | select(.[-1] == $both[0])) as $p2
      | ($f1 | getpath($p1)) as $a1
      | ($f2 | getpath($p2)) as $a2
      | setpath($p1; $a1 + $a2)
      else .
      end
    else .
    end
  '
jq -n --slurpfile file1 file1.json --slurpfile file2 file2.json '
  $file1[0] as $f1
  | $file2[0] as $f2
  | reduce ($f1 | paths) as $p ($f1+$f2;
      ($f1|getpath($p)) as $v1
      | ($f2|getpath($p)) as $v2
      | if ($v1 | type == "array") and
           ($v2 | type == "array")
        then setpath($p; $v1 + $v2)
        else .
        end)

'

输出完全符合要求,假设第二个文件已以明显的方式更正,因此它是有效的JSON。

similar@AC-请澄清要求,特别是如果有两个以上的文件。因此,通过“合并”数组,您的意思是获取相应的项并合并它们?仅合并两个文件。我希望将数组元素附加到数组中。通过编辑我的示例,我澄清了数组中的两个元素具有相同的键。因此,基本上,您希望获得oguz ismail链接的语义?连接数组?