在jq中用于sql join的模拟

时间:2014-08-05 04:37:42

标签: shell unix jq

我有以下json:

[
  {"id": "1", "type": "folder", "title": "folder-1"},
  {"id": "2", "type": "folder", "title": "folder-2"},
  {"id": "3", "type": "item", "title": "item-1", "folder": "1"},
  {"id": "4", "type": "item", "title": "item-2", "folder": "2"},
  {"id": "5", "type": "item", "title": "item-3"}
]

基本上,我需要使用jq生成此输出,这类似于sql join的结果:

[
  {"type": "item", "title": "item-1", "folder": "folder-1"},
  {"type": "item", "title": "item-2", "folder": "folder-2"},
  {"type": "item", "title": "item-3"}
]

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

试试这个过滤器:

map(
    (select(.type=="item") | { key: .folder, value: { type, title } }),
    (select(.type=="folder") | { key: .id, value: { folder: .title } })
)
| group_by(.key)
| map(
    (map(select(.key != null) | .value) | add)
    // map(.value)[]
)

你必须将其分解为步骤。

  1. 获取项目和文件夹,并为每个项目和文件夹获取您感兴趣的值,并为其指定一个与之关联的密钥。

    map(
        (select(.type=="item") | { key: .folder, value: { type, title } }),
        (select(.type=="folder") | { key: .id, value: { folder: .title } })
    )
    
  2. 按键分组

    | group_by(.key)
    
  3. 然后组合具有键(文件夹)的值和其他值

    | map(
        (map(select(.key != null) | .value) | add)
        // map(.value)[]
    )
    

答案 1 :(得分:0)

jq 'map(select(has("folder") or (.["title"] | startswith("item"))) | del(.id))' sample_file

输出:

[
  {
    "type": "item",
    "title": "item-1",
    "folder": "1"
  },
  {
    "type": "item",
    "title": "item-2",
    "folder": "2"
  },
  {
    "type": "item",
    "title": "item-3"
  }
]

答案 2 :(得分:0)

这是另一种解决方案,它将数据分成两个对象$folders$items,然后构建所需的结果。

  (
    reduce map(select(.type == "folder"))[] as $f (
      {}
    ; .[$f.id] = $f
    )
  ) as $folders

| (
    reduce map(select(.type == "item"))[] as $i (
      {}
    ; .[$i.id] = $i
    ) 
  ) as $items

| [
      $items[]
    | {type, title, folder}
    | if .folder == null then del(.folder) else .folder = $folders[.folder].title end
  ]

如果您的jq版本有INDEX/2

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr|
      if type != "string" then tojson
      else .
      end] |= $row);

这可以简化为

  INDEX(.[] | select(.type == "folder"); .id) as $folders
| INDEX(.[] | select(.type == "item"); .id) as $items
| [
      $items[]
    | {type, title, folder}
    | if .folder == null then del(.folder) else .folder = $folders[.folder].title end
  ]