如何使用jq从json创建具有可变数组长度的csv

时间:2016-03-23 18:05:20

标签: json csv jq

我有一个格式如下的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和foreach函数中有一个长度函数,但是后来我在管道中纠结了如何遍历会话部分的数组。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

如果您有数组,请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"

如果存在多个[],则将生成组合的笛卡尔积。 e.g。

$ 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通常很有用。 e.g。

$ 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