2

我有以下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"}
]

有任何想法吗?

4

3 回答 3

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)[]
    )
    
于 2014-08-05T19:18:15.087 回答
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"
  }
]
于 2014-08-05T12:41:55.063 回答
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
  ]
于 2017-08-25T15:10:28.380 回答