【问题标题】:jq merge json via dynamic sub keysjq 通过动态子键合并 json
【发布时间】:2022-01-14 17:27:07
【问题描述】:

我想我离弄清楚如何通过 filter 将一个键 jq reduce 转换为另一个对象子键还差了一步。

我正在尝试合并文件(简化自 Elasticsearch 的 ILM ExplainILM Policy API 响应):

$ echo '{".siem-signals-default": {"modified_date": "siem", "version": 1 }, "kibana-event-log-policy": {"modified_date": "kibana", "version": 1 } }' > ip1.json
$ echo '{"indices": {".siem-signals-default-000001": {"action": "complete", "index": ".siem-signals-default-000001", "policy" : ".siem-signals-default"} } }' > ie1.json

这样生成的 JSON 是:

{
  ".siem-signals-default-000001": {
    "modified_date": "siem",
    "version": 1
    "action": "complete",
    "index": ".siem-signals-default-000001",
    "policy": ".siem-signals-default"
  }
}

其中 ie1 是基本 JSON 并且对于子对象,其子元素 policy 应与 ip1 的键对齐并将其子元素复制到自身中。我一直在尝试构建 thisthisthis(来自 StackOverflow,也来自外部来源的 thisthisthis)。我将在这些基础上列出各种兔子洞尝试,但它们都不够:

$ ((cat ie1.json | jq '.indices') && cat ip1.json) | jq -s 'map(to_entries)|flatten|from_entries' | jq '. as $v| reduce keys[] as $k({}; if true then .[$k] += $v[$k] else . end)'
{
  ".siem-signals-default": {
    "modified_date": "siem",
    "version": 1
  },
  ".siem-signals-default-000001": {
    "action": "complete",
    "index": ".siem-signals-default-000001",
    "policy": ".siem-signals-default"
  },
  "kibana-event-log-policy": {
    "modified_date": "kibana",
    "version": 1
  }
}
$ jq --slurpfile ip1 ip1.json '.indices as $ie1|$ie1+{ilm: $ip1 }' ie1.json
{
  ".siem-signals-default-000001": {
    "action": "complete",
    "index": ".siem-signals-default-000001",
    "policy": ".siem-signals-default"
  },
  "ilm": [
    {
      ".siem-signals-default": {
        "modified_date": "siem",
        "version": 1
      },
      "kibana-event-log-policy": {
        "modified_date": "kibana",
        "version": 1
      }
    }
  ]
}

我也希望这样的东西可以工作,但它编译错误

$ jq -s ip1 ip1.json '. as $ie1|$ie1 + {ilm:(keys[] as $k; $ip1 | select(.policy == $ie1[$k]) | $ie1[$k]  )}' ie1.json
jq: error: ip1/0 is not defined at <top-level>, line 1:
ip1
jq: 1 compile error

从这里你可以看到,我已经确定了加入单独文件的各种方法,但是虽然我有我认为可以用于过滤的代码,但它不正确/不生效。有谁知道如何让过滤器部分工作? TIA

【问题讨论】:

  • 那些键不匹配,这是故意的吗?

标签: json bash jq


【解决方案1】:

这假设您尝试将存储在ie1.json 中的.indices 对象与存储在ip1.json 中的对象中的一个对象组合在一起。由于要匹配的键不同,我进一步假设您想要匹配来自.indices 对象的字段名称,通过切断最后一个破折号- 之后的所有内容来减少对象中的相同键ip1.json.

为此,ip1.jsoninput 读入为$ip(或者你可以使用jq --argfile ip ip1.json),然后.indices 对象从第一个输入ie1.json 和通过with_entries(.value …) 访问的内部对象在匹配时添加了在$ip 中查找的结果,并相应地减少了.key

jq '
  input as $ip | .indices | with_entries(.value += $ip[.key | sub("-[^-]*$";"")])
' ie1.json ip1.json
{
  ".siem-signals-default-000001": {
    "action": "complete",
    "index": ".siem-signals-default-000001",
    "policy": ".siem-signals-default",
    "modified_date": "siem",
    "version": 1
  }
}

Demo

如果您希望将字段.index 的内容作为参考而不是.indices 对象的内部字段nane(在您的示例数据中具有相同的值),您可以使用map_values 而不是@987654343 @ 因为您不再需要该字段的名称。

jq '
  input as $ip | .indices | map_values(. += $ip[.index | sub("-[^-]*$";"")])
'ie1.json ip1.json

Demo

注意:我使用带有正则表达式的sub 来操作键名,如果实际上它更复杂,您可以根据自己的喜好轻松调整。但是,如果该模式实际上就像在最后一个破折号后切断一样简单,那么使用 .[:rindex("-")] 也可以完成工作。

【讨论】:

  • 啊,耶!谢谢!这很完美。我让这种方式比它需要的更复杂。干杯。
【解决方案2】:

我还收到了一个简单的“适用于我的用例”但不是确切答案的离线反馈:

$ jq '.indices | map(. * input[.policy])' ie1.json ip1.json
[
  {
    "action": "complete",
    "index": ".siem-signals-default-000001",
    "policy": ".siem-signals-default",
    "modified_date": "siem",
    "version": 1
  }
]

发布以防有人遇到类似情况,但其他答案更好。

【讨论】:

    猜你喜欢
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    • 2019-03-24
    相关资源
    最近更新 更多