在jq中取消嵌套对象时,如何避免在管道的每个阶段都重新声明标签?

时间:2019-01-16 04:45:16

标签: json jq

摘要:

我已经成功地弄清了如何取消jq中对象的嵌套;但是,我编写的工作代码需要大量重复。我觉得可能有一种更简洁或更简洁的方法来实现相同的结果,我想知道它是什么。

示例:

使用以下嵌套的公司结构,假设目标是为列出的每个提取名称,ID,公司和站点。 (我们可以忽略该地址。)

输入:

{
  "company": "Initrode",
  "sites": [
    {
      "name": "HQ",
      "address": "123 Main Street",
      "personnel": [
        {
          "name": "John Smith",
          "UID": 12345
        },
        {
          "name": "Jane Doe",
          "UID": 23456
        }
      ]
    },
    {
      "name": "Branch Office",
      "address": "Spodunk, Nowhereville",
      "personnel": [
        {
          "name": "Fred Anderson",
          "UID": 56789
        },
        {
          "name": "Bill Jones",
          "UID": 34567
        }
      ]
    }
  ]
}
{
  "company": "Inittech",
  "sites": [
    {
      "name": "Main Office",
      "address": "5678 Avenue Blvd",
      "personnel": [
        {
          "name": "Fred Johnson",
          "UID": 6543
        },
        {
          "name": "James Fredson",
          "UID": 9876
        }
      ]
    },
    {
      "name": "Testing Station",
      "address": "Alaskan Wilderness",
      "personnel": [
        {
          "name": "Sally May",
          "UID": 5432
        },
        {
          "name": "Jack James",
          "UID": 8765
        }
      ]
    }
  ]
}

工作代码:

jq '{company,site: .sites[]}|
{company,site: .site.name,personnel: .site.personnel[]}|
{name: .personnel.name,id: .personnel.UID,company,site}' sample.json

正确的输出:

{
  "name": "John Smith",
  "id": 12345,
  "company": "Initrode",
  "site": "HQ"
}
{
  "name": "Jane Doe",
  "id": 23456,
  "company": "Initrode",
  "site": "HQ"
}
{
  "name": "Fred Anderson",
  "id": 56789,
  "company": "Initrode",
  "site": "Branch Office"
}
{
  "name": "Bill Jones",
  "id": 34567,
  "company": "Initrode",
  "site": "Branch Office"
}
{
  "name": "Fred Johnson",
  "id": 6543,
  "company": "Inittech",
  "site": "Main Office"
}
{
  "name": "James Fredson",
  "id": 9876,
  "company": "Inittech",
  "site": "Main Office"
}
{
  "name": "Sally May",
  "id": 5432,
  "company": "Inittech",
  "site": "Testing Station"
}
{
  "name": "Jack James",
  "id": 8765,
  "company": "Inittech",
  "site": "Testing Station"
}

问题:

这里涉及很多重复。除了在流水线的每个阶段重复外部标签之外,在流水线的第二部分和第三部分还分别重复了.site.personnel

我的真实数据要复杂得多,所以这种重复甚至更糟,更难阅读。

顺便说一下,下面是我为实现上述相同目标而尝试的一些非工作代码:

jq '{company,site: .sites[].name,name: .sites[].personnel[].name,id: .sites[].personnel[].UID}' sample.json

重复的次数要少得多,但是不幸的是,它返回与公司每个ID和站点相关联的每个人-错误的结果,例如数据库“交叉连接”而不是“内部连接”。

我不太了解如何用文字描述此处需要的内容,但希望上面的示例可以帮助您弄清楚。

一种描述它的方法是,我试图将子对象数组中的多个名称/值对合并到顶级对象中,而不将来自的名称/值对的任何组合一起返回相同数组值内的子对象。但是,即使对于我来说,这也不是一件容易的事。因此,上面的示例输入/输出。


仅出于兴趣,这是我拥有的真实工作代码,属性名称被混淆了:

jq '.pears[]|{pear: .name,file: .somepath,toBeFiltered: (.appletypes[]|select(.name == "orange")|.bananas[]|{banana: .name,apples: .apples[]})}|{pear,file,banana: .toBeFiltered.banana,applestem: .toBeFiltered.apples.applestem,orangecomment: (.toBeFiltered.apples.peaches[]|select(.akey == "string")|.avalue.value),linenumber: (.toBeFiltered.apples.peaches[]|select(.akey == "string")|.line)}' realfile.json

1 个答案:

答案 0 :(得分:1)

也许您缺少的是jq变量的实用程序:

.company as $company
| .sites[]
| .name as $site
| .personnel[]
| { name, id: .UID, company: $company, site: $site }

但是,也可以通过使用括号来避免变量。如果您不介意按键的顺序略有不同,则可以这样写:

(.sites[] | ( (.personnel[] | { name, id: .UID} ) +  {site: .name} )) + {company} 

如果键必须按照Q中显示的顺序,则只需将以下过滤器附加到上述管道中即可:

{name, id, company, site}