【问题标题】:tag jq how to combine multiple paths into one objecttag jq 如何将多个路径组合成一个对象
【发布时间】:2017-07-23 21:56:50
【问题描述】:

我有一个对象,我可以过滤到我希望保留的多个路径。路径的形式为:

[
  "key1",
  "key2",
  "mykey"
]
[
  "key3",
  "key4",
  "mykey"
]

我想要的是:

{ "key1":{
      "key2": .key2
       },
  "key3":{
      "key4": .key4
       }
}

我能得到的最接近的是:

{ "key1":{
   "key2": .key2
      }
}
{  "key3":{
      "key4": .key4
}

使用:

(paths(objects)|select(last(.[])=="mykey")) as $path|
getpath([$path[0],$path[1]]) as $getpath|
{($path[0]):{($path[1]):$getpath}}

虽然我可以将此输出通过管道传输到 jq -s '.'命令,我找不到将原始过滤器集中的路径重建相加的方法。过滤器似乎在每个对象的末尾重置。 $path 似乎一次只保存一个路径数组,而不是一个路径数组。这可以防止我在 reduce 函数中迭代 $path。

我创建了以下有效的脚本,但我也有兴趣了解如何使用 paths() 函数。到目前为止,我还没有想出如何让它对我非常有用。

(to_entries |
 map(select(.["value"][]?|has("mykey")?))|[.[].key]) as $rooms|
(to_entries |
 map(select(.["value"][]?|has("mykey")?))|[.[].value]) as $roomvals| #allows room paths to be avail

##### creates object containing only those locations and sensors within the locations that include "mykey" objs

reduce
range(0;$rooms|length) as $i ({};
.+{($rooms[$i]): ($roomvals[$i] | to_entries |
map(select(.["value"]|has("mykey")))|{(.[]["key"]):.[]["value"]})})

对这些方法的任何帮助或替代方法的建议表示赞赏。

【问题讨论】:

    标签: json object filtering jq


    【解决方案1】:

    在 peak 回答的指导下,我现在可以更好地提出和回答我的问题。

    我已经扩展了 peak 在他的示例中使用的数据对象,以便更好地代表我试图解决的问题。现在数据更好地说明了“key2”和“key10”有“mykey”,而“key6”、“key8”和“key11”没有。我想在我的问题中表达的是我想保留“key2”和“key10”的完整路径,其中包括“another”和“mykey”。我意识到对 peak 的示例选择标准进行小的修改就可以做到这一点。我只需要在选择中添加一个过滤器即可保留每个路径的第一个两个元素,其中包括“mykey”:

    def data: 
      { "key1": { "key2": {"mykey": {"a": 123},
                           "another":{"q": "six"} },
                  "key6": {"key7": {"d": 997} } },
        "key3": { "key8": {"key9": {"b": 234} },
                  "key10": {"mykey": {"d": 997},
                           "another":{"q": "seven"} } },
        "key4": { "key11": {"key5" : {"a": 123} } }
      };
    
    def selection(mykey):
    
      . as $in 
      | reduce (paths(objects) | select(last(.[])==mykey)|.[0:2]) as $path
          (null; setpath($path; $in|getpath($path)) );
    
    data | selection("mykey")
    

    返回我想要的:

    {"key1":{"key2":{"mykey":{"a":123},
                     "another":{"q":"six"}}},
     "key3":{"key6":{"mykey":{"d":997},
                     "another":{"q":"seven"}}}
    }
    

    您会注意到现在的选择包括“|.[0:2]”。

    感谢 peak 让我走上正轨。我投票支持他的回答,因为它帮助我更好地表达我的问题并让我有洞察力来解决它。

    【讨论】:

      【解决方案2】:

      您表示想要的输出不是 JSON,我不清楚所需的输出是什么,但以下内容似乎很接近:

      reduce inputs as $d (null; setpath( $d[0: ($d|length) - 1]; $d[-1] ) )
      

      根据您的输入并使用 jq -n,这会产生:

      {
        "key1": {
          "key2": "mykey"
        },
        "key3": {
          "key4": "mykey"
        }
      }
      

      希望你能从这里拿走它。

      示例:

      def data: 
        { "key1": { "key2": {"mykey": {"a": 123} } },
          "key3": { "key4": {"mykey": {"b": 234} } },
          "key4": { "key1": {"key2" : {"a": 123} } }
        };
      
      def selection(mykey):
        . as $in
        | reduce (paths(objects) | select(.[-1] == mykey)) as $path
            (null; setpath($path; $in|getpath($path)) );
      
      data | selection("mykey")
      

      调用:jq -n -c -f example.jq

      输出:

      {"key1":{"key2":{"mykey":{"a":123}}},
       "key3":{"key4":{"mykey":{"b":234}}}}
      

      【讨论】:

      • 作为 JSON 新手,我可能没有选择正确的方式来说明我想要什么。主要对象“key1”和“key3”具有子对象,而子对象又具有“mykey”子对象。没有说明的是“mykey”只是对象“key2”和“key4”的几个子对象之一"。{"key2": .key2} 可能以另一种方式更好地表示,比如{"key2": getpath("key2")}。顺便说一句,我找不到您在 jq 手册中使用的“数据”关键字的参考。它有什么作用?
      • “数据”在这里应该是“输入”。您是否尝试生成 JSON 输出?
      猜你喜欢
      • 2018-09-15
      • 1970-01-01
      • 1970-01-01
      • 2018-12-31
      • 2019-06-18
      • 2019-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多