jq merge json 通过动态子键

jq merge json via dynamic sub keys

我想我离弄清楚如何将一个键 reduce via filter 转换为另一个对象的子键还有一步。

我正在尝试合并文件(根据 Elasticsearch 的 ILM Explain & ILM 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 的键对齐并将其子元素复制到自身中。我一直在尝试从外部来源构建 this, this, and this (from Whosebug, also this, this, this)。我将列出以这些为基础的各种兔子洞尝试,但它们都不够:

$ ((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

这假设您正在尝试将存储在 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 而不是 with_entries,因为您不再需要该字段的名称。

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

Demo

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

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

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

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