【问题标题】:How to make a csv from json with variable array lengths using jq如何使用 jq 从 json 制作具有可变数组长度的 csv
【发布时间】:2016-03-23 18:05:20
【问题描述】:

我有一个格式如下的 JSON

{
    "type": "conversation",
    "id": "1234",
    "created_at": 1425586662,
    "initial_message": {
        "type": "initial_message",
        "id": "567",
        "body": "<p>Testing</p>",
        "author": {
            "type": "admin",
            "id": "9382"
        }
    },
    "conversation_parts": {
        "type": "conversation_part.list",
        "conversation_parts": [
            {
                "type": "conversation_part",
                "id": "6789",
                "part_type": "comment",
                "body": "<p>Good test</p>",
                "created_at": 1425586731,
                "author": {
                    "type": "user",
                    "id": "029384"
                }
            },
            {
                "type": "conversation_part",
                "id": "9384",
                "part_type": "close",
                "body": null,
                "created_at": 1425929944,
                "author": {
                    "type": "admin",
                    "id": "9382"
            }
        ]
    }
}

总是有一个initial_message,但对话部分数组中可能有也可能没有,并且该数组可能有任意数量的成员。

我正在尝试在 csv 中捕获其中的一些信息,尽管 @csv 函数我没有运气

我试过了:

jq '"\(.type), \(.id), \(.created_at), \(.initial_message.type), \(.initial_message.id), \(.initial_message.author.type), \(.conversation_parts.conversation_parts[].part), \(.conversation_parts.conversation_parts[].id), \(.conversation_parts.conversation_parts[].part_type), \(.conversation_parts.conversation_parts[].created_at), \(.conversation_parts.conversation_parts[].author.type)"' \

但它为我提供了数组中所有可能的事物组合(我从这个示例中得到 32 行结果)。

为了简洁起见,我正在编辑我正在寻找的信息总量,但我的理想是显示

1234, 567, initial, admin
1234, 6789, comment, user
1234, 9384, close, admin

如果我能做到就好了

1234, 567, admin, 6789, comment, user
1234, 567, admin, 9384, close, admin

我不能拥有的是

1234, 567, admin, 6789, comment, user
1234, 567, admin, 9384, comment, admin
1234, 567, admin, 6789, close, user
1234, 567, admin, 9384, close, admin

这就是我现在得到的

我知道 jq 中有一个 length 函数和一个 foreach 函数,但是我在管道中纠结于如何循环遍历对话部分的数组。任何帮助将不胜感激!

【问题讨论】:

    标签: json csv jq


    【解决方案1】:

    jq 中,如果你有一个数组,例如

    [1,2,3]
    

    然后string interpolationobject construction 过滤器使用[] 数组迭代将生成多个字符串或对象,例如

    $ jq -Mnc '[1,2,3] | {x:.[]}'
    {"x":1}
    {"x":2}
    {"x":3}
    
    $ jq -Mnc '[1,2,3] | "x:\(.[])"'
    "x:1"
    "x:2"
    "x:3"
    

    如果存在多个[],则将产生组合的笛卡尔积。例如

    $ jq -Mnc '[1,2,3] | "x:\(.[]) x:\(.[])"'
    "x:1 x:1"
    "x:2 x:1"
    "x:3 x:1"
    "x:1 x:2"
    "x:2 x:2"
    "x:3 x:2"
    "x:1 x:3"
    "x:2 x:3"
    "x:3 x:3"
    

    如果这不是您想要的,避免它的简单方法是将 [] 移出插值,例如

    $ jq -Mnc '[1,2,3] | .[] | "x:\(.) x:\(.)"'
    "x:1 x:1"
    "x:2 x:2"
    "x:3 x:3"
    

    此外,variable binding 在使用嵌套结构时通常很有帮助。例如

    $ jq -Mnc '{a:100, b:[1,2,3]} | .a as $a | .b[] | "a:\($a) b:\(.)"'
    "a:100 b:1"
    "a:100 b:2"
    "a:100 b:3"
    

    最后,这里有一个过滤器,它使用这些功能来解决这个问题。 Functions 用于保持处理初始消息和对话部分的逻辑分开。

    def initial:
        .id as $id
      | .initial_message
      |   .type as $ity
      |   .id   as $iid
      |   .author
      |     .type as $iaty
      |     "\($id), \($iid), \($ity), \($iaty)"
    ;
    
    def parts:
        .id as $id
      | .conversation_parts.conversation_parts[]  # note [] here
      |   .id as $cid
      |   .part_type as $cpt
      |   .author
      |     .type as $caty
      |     "\($id), \($cid), \($cpt), \($caty)"
    ;
    
      initial
    , parts
    

    如果filter.jq 包含此过滤器并且data.json 包含样本数据,则

    $ jq -M -r -f filter.jq data.json
    

    会产生

    1234, 567, initial_message, admin
    1234, 6789, comment, user
    1234, 9384, close, admin
    

    【讨论】:

      猜你喜欢
      • 2020-02-16
      • 1970-01-01
      • 2020-04-08
      • 1970-01-01
      • 1970-01-01
      • 2021-04-01
      • 2021-07-12
      • 2020-07-26
      • 1970-01-01
      相关资源
      最近更新 更多