jq条件处理多个文件

时间:2017-10-30 15:10:14

标签: json jq

我有多个json文件:

a.json

{
  "status": "passed",
  "id": "id1"
}
{
  "status": "passed",
  "id": "id2"
}

b.json

{
  "status": "passed",
  "id": "id1"
}
{
  "status": "failed",
  "id": "id2"
}

我想知道a.json中传递了哪个ID,而b.json中哪个ID失败了。

expected.json

{
  "status": "failed",
  "id": "id2"
}

我尝试过类似的事情:

jq --slurpfile a a.json --slurpfile b b.json -n '$a[] | reduce select(.status == "passed") as $passed (.; $b | select($a.id == .id and  .status == "failed"))'

$passed应该包含a.json中传递的条目列表,而reduce将合并id匹配且failed的所有对象。

但是它没有产生预期的结果,文档也有限。

如何从expected.jsona.json生成b.json

2 个答案:

答案 0 :(得分:2)

对我来说,你的过滤器会产生错误

jq: error (at <unknown>): Cannot index array with string "id"

我怀疑这是因为你写了$b而不是$b[]$a.id而不是$passed.id。以下是我对你打算写的内容的猜测:

  $a[] 
| reduce select(.status == "passed") as $passed (.; 
   $b[] | select( $passed.id == .id and .status == "failed")
  )

产生输出

null
{
  "status": "failed",
  "id": "id2"
}

您可以通过添加null例如

来过滤掉| values
  $a[] 
| reduce select(.status == "passed") as $passed (.; 
   $b[] | select( $passed.id == .id and .status == "failed")
  )
| values

但是这里你真的不需要reduce。一种更简单的方法就是:

   $a[]
 | select(.status == "passed") as $passed
 | $b[]
 | select( $passed.id == .id and .status == "failed")

如果你想进一步研究这个问题,我建议采用另一种方法:首先构建一个组合$a$b的对象,然后根据需要设计你想要的对象。 e.g。

reduce (($a[]|{(.id):{a:.status}}),($b[]|{(.id):{b:.status}})) as $v ({};.*$v)

会给你

{
  "id1": {
    "a": "passed",
    "b": "passed"
  },
  "id2": {
    "a": "passed",
    "b": "failed"
  }
}

要将其转换回您请求的输出,请添加

 | keys[] as $id
 | .[$id]
 | select(.a == "passed" and .b == "failed")
 | {$id, status:.b}

获取

{
  "id": "id2",
  "status": "failed"
}

答案 1 :(得分:1)

以下问题的解决方案主要针对效率,但事实证明它们非常简单明了。

为了提高效率,我们将构建一个&#34;字典&#34;那些已经通过a.json来快速完成所需查找的人的ID。

另外,如果您的jq版本为inputs,则很容易避免&#34;啜饮&#34; b.json的内容。

jq 1.4或更高版本的解决方案

这是一个通用的解决方案,然而,它会淹没这两个文件:

调用(注意使用-s选项):

jq -s --slurpfile a a.json -f passed-and-failed.jq b.json

程序:

([$a[] | select(.status=="passed") | {(.id): true}] | add) as $passed
| .[] | select(.status == "failed" and $passed[.id])

即,首先构造字典,然后在b.json中发出满足条件的对象。

jq 1.5或更高版本的解决方案

调用(注意使用-n选项):

jq -n --slurpfile a a.json -f passed-and-failed.jq b.json

INDEX/2目前可从master分支获得,但此处提供以防您的jq没有它,在这种情况下,您可能希望将其定义添加到~/.jq

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr|
      if type != "string" then tojson
      else .
      end] |= $row);

解决方案现在变成了一个简单的双线程:

INDEX($a[] | select(.status == "passed") | .id; .) as $passed
| inputs | select(.status == "failed" and $passed[.id])