简体   繁体   English

JQ:如何使用jq挑选的数据创建JSON object?

[英]JQ: How to create JSON object using data picked by jq?

I have a complex JSON file that contains hundreds of "attributes" with their types identified by "objectTypeAttributeId".我有一个复杂的 JSON 文件,其中包含数百个“属性”,其类型由“objectTypeAttributeId”标识。

I know that objectTypeAttributeId=328 means tickedid, objectTypeAttributeId=329 contains array of hostnames etc..我知道 objectTypeAttributeId=328 表示 tickedid,objectTypeAttributeId=329 包含主机名数组等。

There is simplified version of the file:该文件有简化版本:

{
  "objectEntries": [
    {
      "attributes": [
        {
          "id": 279792,
          "objectTypeAttributeId": 328,
          "objectAttributeValues": [
            {
              "displayValue": "ITSM-24210"
            }
          ]
        },
        {
          "id": 279795,
          "objectTypeAttributeId": 329,
          "objectAttributeValues": [
            {
              "displayValue": "testhost1"
            },
            {
              "displayValue": "testhost2"
            }
          ]
        },
        {
          "id": 279793,
          "objectTypeAttributeId": 330,
          "objectAttributeValues": [
            {
              "displayValue": "28.02.2020 11:45"
            }
          ]
        }
      ]
    }
  ]
}

I need to create output JSON using particular values picked out (according to the "objectTypeAttributeId" value) of input JSON in format like this:我需要使用从输入 JSON 中挑选出的特定值(根据“objectTypeAttributeId”值)创建 output JSON,格式如下:

{
    "tickets": [
        {
            "ticketid": "ITSM-24210",
            "hostnames": ["testhost1", "testhost2"],
            "date": "28.02.2020 11:45"
        }
    ]
}

I am new in jq, in the XSLT it is solvable using static template with placeholders for picked values.我是 jq 的新手,在 XSLT 中,它可以使用 static 模板和占位符来选择值来解决。

I have tried this approach, there is my jq filter:我试过这种方法,有我的 jq 过滤器:

.objectEntries[].attributes[] |
  {ticketid: select(.objectTypeAttributeId == 328) | .objectAttributeValues[0].displayValue},
  {hostnames: select(.objectTypeAttributeId == 329) | [.objectAttributeValues[].displayValue]},
  {date: select(.objectTypeAttributeId == 330) | .objectAttributeValues[0].displayValue}

but the result of this approach is:但这种方法的结果是:

{
  "ticketid": "ITSM-24210"
}
{
  "hostnames": [
    "testhost1",
    "testhost2"
  ]
}
{
  "date": "28.02.2020 11:45"
}

And all my subsequent tries to format output better ends in broken jq filter or filter that does not return anything.我随后尝试格式化 output 更好地以损坏的 jq 过滤器或不返回任何内容的过滤器结束。

Please any ideas how to solve this problem?请任何想法如何解决这个问题?

Assuming a ticket is to be generated for each object entry:假设要为每个 object 条目生成一张票:

{tickets: [
  .objectEntries[]
  | [.attributes[]
    | [.objectTypeAttributeId,
      (.objectAttributeValues | map(.displayValue))] as [$id, $val]
    |   if $id == 328 then {ticketId:  $val[0]}
      elif $id == 329 then {hostnames: $val}
      elif $id == 330 then {date:      $val[0]}
      else empty end
  ] | add
]}

Online demo在线演示

Here we go, it's not pretty, there may be a better solution but it works: https://jqplay.org/s/sxussfa2Vj我们在这里 go,它不是很漂亮,可能有更好的解决方案但它有效: https://jqplay.org/s/sxussfa2Vj

.objectEntries | {tickets: map(.attributes | 
{ticketID: (reduce .[] as $r (null;  if $r.objectTypeAttributeId == 328 
then $r.objectAttributeValues[0].value else . end)),
date: (reduce .[] as $r (null;  if $r.objectTypeAttributeId == 330
then $r.objectAttributeValues[0].value else . end)), 
hostnames: (reduce .[] as $r ([];  if $r.objectTypeAttributeId == 329 
then $r.objectAttributeValues | map(.value) else . end))})}

There's a lot of unpacking and repacking going on here that sort of distracts from the core.这里有很多拆包和重新包装,有点分散了核心的注意力。 You have an array of tickets (aka entries), and over those we map. The various properties we have to grab from different entries of an array, which is done using reduce.您有一组票证(也称为条目),在这些票证上我们有 map。我们必须从数组的不同条目中获取各种属性,这是使用 reduce 完成的。 Reduce goes through the array of objects and picks out the right one and keeps track of the value. Reduce 遍历对象数组并挑选出正确的对象并跟踪值。

Maybe there's a nice way, but this works already, so you can play with it further, trying to simplify.也许有一个不错的方法,但这已经有效,因此您可以进一步尝试,尝试简化。

Your original solution almost works, you did a good job there, just needed a map:你原来的解决方案几乎可以工作,你在那里做得很好,只需要一个 map:

.objectEntries[].attributes | 
{ticketid: . | map(select(.objectTypeAttributeId == 328))[0] | 
.objectAttributeValues[0].displayValue, 
date: . | map(select(.objectTypeAttributeId == 330))[0] |
.objectAttributeValues[0].displayValue, 
hostnames: . | map(select(.objectTypeAttributeId == 329))[0] | 
[.objectAttributeValues[].displayValue]}

Try it out, it even works with multiple tickets;) https://jqplay.org/s/ydoCgv9vsI试试看,它甚至适用于多张票;) https://jqplay.org/s/ydoCgv9vsI

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM