【问题标题】:Parse json and extract items in array upon condition of nested values根据嵌套值的条件解析 json 并提取数组中的项目
【发布时间】:2015-07-21 13:24:24
【问题描述】:

我已经在这里问过类似的问题 - Parse json and choose items\keys upon condition,但这次略有不同。

这是一个例子:

[
  {
    "item1": "value123",
    "array0": [
      {
        "item2": "aaa"
      }
    ]
  },
  {
    "item1": "value456",
    "array1": [
      {
        "item2": "bbb"
      }
    ]
  },
  {
    "item1": "value789",
    "array2": [
      {
        "item2": "ccc"
      }
    ]
  }
]

我想获取“item1”的值,只有当“item2”具有特定值时。

假设 item2 等于“bbb”,那么我想要返回的只是“value456”。

我尝试使用 jq 解决它,就像它在上述问题中对我有用,但无济于事,因为我无法从比我正在搜索的“更高”级别提取值jq 的选择和映射。

【问题讨论】:

    标签: json rest parsing conditional-statements jq


    【解决方案1】:

    由于递归运算符.. 的魔力,可以使用更简单的解决方案:

    jq -r '.[] | select(.. | .item2? == "bbb").item1'

    基本上这样做是,对于原始数组中的每个 (.[]) 对象,仅选择 (select) 那些名为 .item2 的任何键递归 (..) 等于 "bbb" ,然后选择该对象的.item1 属性。

    【讨论】:

      【解决方案2】:

      在 jq 的手册中找到了解决方案(使用 #ifthenelse 和 #Objects)-http://stedolan.github.io/jq/manual

      jq -r '{name1: .[].item1, name2: .[].array[].item2} | /
      if .item2 == "bbb" then .name1 elif .item2 != "bbb" then empty else empty end'
      

      【讨论】:

      • 但是这个脚本实际上并不适用于您在上面提供的 JSON 对象,是吗?它期望为每个底层对象调用数组array,而不是一直使用不同的名称。在这种假设下,您也不需要递归运算符:您只需 jq -r '.[] | select(.array.item2 == "bbb").item1'
      • 确实如此。没有从全局角度考虑脚本,只是希望它适用于我的情况:)。感谢您的补充。
      【解决方案3】:

      如果您发现 .. 的魔力对于您的目的来说太强大了,以下内容可能会有用。它限制了对“item2”键的搜索。

      def some(condition): reduce .[] as $x
       (false; if . then . else $x|condition end);
      
      .[]
      | to_entries
      | select( some( .value | (type == "array") and some(.item2 == "bbb")) )
      | from_entries
      | .item1
      

      如果您的 jq 有 any/1,则使用它而不是 some/1。

      【讨论】:

        【解决方案4】:

        这是一个使用 tostream 和 getpath

        的解决方案
        foreach (tostream|select(length==2)) as [$p,$v] (.;.;
          if $p[-1] == "item2" and $v == "bbb" then getpath($p[:-3]).item1 else empty end
        )
        

        编辑:我现在意识到 foreach E as $X (.; .; R) 形式的过滤器几乎总是可以重写为 E as $X | R 所以上面真的只是

          (tostream | select(length==2)) as [$p,$v]
        | if $p[-1] == "item2" and $v == "bbb" then getpath($p[:-3]).item1 else empty end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-08
          • 1970-01-01
          • 1970-01-01
          • 2016-05-31
          • 2022-01-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多