将JSON类别树转换为数据库表

时间:2017-10-23 18:56:01

标签: json csv recursion jq flatten

想象一下,我有一个像这个JSON文件的类别树:

[
  {
    "id": "1",
    "text": "engine",
    "children": [
      {
        "id": "2",
        "text": "exhaust",
        "children": []
      },
      {
        "id": "3",
        "text": "cooling",
        "children": [
          {
            "id": "4",
            "text": "cooling fan",
            "children": []
          },
          {
            "id": "5",
            "text": "water pump",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "id": "6",
    "text": "frame",
    "children": [
      {
        "id": "7",
        "text": "wheels",
        "children": []
      },
      {
        "id": "8",
        "text": "brakes",
        "children": [
          {
            "id": "9",
            "text": "brake calipers",
            "children": []
          }
        ]
      },
      {
        "id": "10",
        "text": "cables",
        "children": []
      }
    ]
  }
]

如何将其转换为此平台?

id  parent_id   text
1   NULL        engine
2   1           exhaust
3   1           cooling
4   3           cooling fan
5   3           water pump
6   NULL        frame
7   6           wheels
8   6           brakes
9   8           brake calipers
10  6           cables

我发现了类似的问题和反向问题(从表格到JSON)但我无法用jq及其@tsv过滤器来解决这个问题。另外我注意到答案中经常引用“flatten”过滤器(虽然它看起来是我需要的确切工具),但可能是因为它最近在jq的最新版本中被引入。

3 个答案:

答案 0 :(得分:1)

这里的关键是定义一个递归函数,如下所示:

def children($parent_id):
  .id as $id
  | [$id, $parent_id, .text],
    (.children[] | children($id)) ;

使用您的数据,过滤器:

.[]
| children("NULL")
| @tsv

生成如下所示的制表符分隔值。现在可以轻松添加标题,如果需要,可以转换为固定宽度格式等。

1   NULL    engine
2   1   exhaust
3   1   cooling
4   3   cooling fan
5   3   water pump
6   NULL    frame
7   6   wheels
8   6   brakes
9   8   brake calipers
10  6   cables

答案 1 :(得分:1)

这是另一个使用jq recurse内置的解决方案:

  ["id","parent_id","text"]
, (
      .[]
    | recurse(.id as $p| .children[] | .parent=$p )
    | [.id, .parent, .text]
  )
| @tsv 

示例运行(假定filter.jq中的过滤器和data.json中的样本数据)

$ jq -Mr -f filter.jq data.json
id  parent_id   text
1       engine
2   1   exhaust
3   1   cooling
4   3   cooling fan
5   3   water pump
6       frame
7   6   wheels
8   6   brakes
9   8   brake calipers
10  6   cables

Try it online!

答案 2 :(得分:0)

这是一个使用递归函数的解决方案:

def details($parent):
   [.id, $parent, .text],                   # details for current node
   (.id as $p | .children[] | details($p))  # details for children
;

  ["id","parent_id","text"]                 # header
, (.[] | details(null))                     # details
| @tsv                                      # convert to tsv

示例运行(假定filter.jq中的过滤器和data.json中的样本数据)

$ jq -Mr -f filter.jq data.json 
id  parent_id   text
1       engine
2   1   exhaust
3   1   cooling
4   3   cooling fan
5   3   water pump
6       frame
7   6   wheels
8   6   brakes
9   8   brake calipers
10  6   cables

Try it online!