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

将JSON类别树转换为数据库表,json,csv,recursion,jq,flatten,Json,Csv,Recursion,Jq,Flatten,假设我有一个类似于JSON文件的类别树: [ { "id": "1", "text": "engine", "children": [ { "id": "2", "text": "exhaust", "children": [] }, { "id": "3", "text": "cooling", "children": [

假设我有一个类似于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过滤器来解决。我还注意到“展平”过滤器在回答中并不经常被引用(虽然它看起来正是我需要的工具),但这可能是因为它最近在最新版本的jq中引入了。

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

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

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

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

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

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
中)


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

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内置的解决方案:

示例运行(假设过滤器在
filter.jq
中,样本数据在
data.json
中)


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

示例运行(假设过滤器在
filter.jq
中,样本数据在
data.json
中)


太棒了!我现在可以在卷曲后直接用卷曲管…|jq-Mr'([]|递归(.id为$p |.children[]|.parent=$p)|[.id,.parent,.text])@tsv'Brilliant!我现在可以在卷曲后直接用卷曲管…|jq-Mr'([]| recurse(.id为$p |.children[]|.parent=$p)|[.id,.parent,.text])@tsv'非常感谢您的回答!最后,我选择了jq170727的应用解决方案,因为它使用了jq内置的递归函数。非常感谢您的回答!最后,我选择了应用jq170727的解决方案,因为它使用了内置于jq的递归函数。