tag jq如何将多个路径组合成一个对象

时间:2017-03-03 17:13:40

标签: json object filtering jq

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

[
  "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"]})})

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

2 个答案:

答案 0 :(得分:0)

您所指示的输出不是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}}}}

答案 1 :(得分:0)

在峰值回应的指导下,我现在可以更好地构建并回答我的问题了。

我扩展了他的示例中使用的峰值数据对象,因此它更好地代表了我试图解决的问题。现在数据更好地说明“key2”和“key10”具有“mykey”,而“key6”,“key8”和“key11”则没有。我想在我的问题中表达的是,我想保留“key2”和“key10”的完整路径,其中包括“另一个”以及“mykey”。我意识到对峰值示例选择标准的一个小修改就可以做到。我只需要在选择中添加一个过滤器,以保留包含“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]”。

感谢您设置我的正确轨道的高峰。我已经投了他的答案,因为它帮助我更好地表达我的问题并给我解决它的见解。