【问题标题】:Is there a way to use jq to split a JSON file by its common keys?有没有办法使用 jq 通过其公共键拆分 JSON 文件?
【发布时间】:2019-01-30 23:05:16
【问题描述】:

我有很多股票的一组定价数据(大约 110 万行)。

我在解析内存中的所有这些数据时遇到问题,因此我想按股票代码将其拆分为单独的文件,并仅在需要时导入数据。

发件人:

stockprices.json

收件人:

AAPL.json
ACN.json
...

等等

stockprices.json 目前有这个结构:

[{
    "date": "2016-03-22 00:00:00",
    "symbol": "ACN",
    "open": "121.029999",
    "close": "121.470001",
    "low": "120.720001",
    "high": "122.910004",
    "volume": "711400.0"
},
{
    "date": "2016-03-23 00:00:00",
    "symbol": "AAPL",
    "open": "121.470001",
    "close": "119.379997",
    "low": "119.099998",
    "high": "121.470001",
    "volume": "444200.0"
},
{
    "date": "2016-03-24 00:00:00",
    "symbol": "AAPL",
    "open": "118.889999",
    "close": "119.410004",
    "low": "117.639999",
    "high": "119.440002",
    "volume": "534100.0"
},
...{}....]

我相信 jq 是适合这项工作的工具,但我无法理解它。

我将如何获取上面的数据并使用 jq 按符号字段对其进行拆分?

例如,我想最终得到:

AAPL.json:

[{
    "date": "2016-03-23 00:00:00",
    "symbol": "AAPL",
    "open": "121.470001",
    "close": "119.379997",
    "low": "119.099998",
    "high": "121.470001",
    "volume": "444200.0"
},
{
    "date": "2016-03-24 00:00:00",
    "symbol": "AAPL",
    "open": "118.889999",
    "close": "119.410004",
    "low": "117.639999",
    "high": "119.440002",
    "volume": "534100.0"
}]

和 ACN.json:

[{
    "date": "2016-03-22 00:00:00",
    "symbol": "ACN",
    "open": "121.029999",
    "close": "121.470001",
    "low": "120.720001",
    "high": "122.910004",
    "volume": "711400.0"
},
    {
    "date": "2016-03-22 00:00:00",
    "symbol": "ACN",
    "open": "121.029999",
    "close": "121.470001",
    "low": "120.720001",
    "high": "122.910004",
    "volume": "711400.0"
}
]

【问题讨论】:

    标签: json file split jq data-partitioning


    【解决方案1】:

    您需要一个循环,但可以在一次调用中完成:

    jq -rc 'group_by(.symbol)[] | "\(.[0].symbol)\t\(.)"' stockprices.json |
    while IFS=$'\t' read -r symbol content; do
        echo "${content}" > "${symbol}.json"
    done
    

    【讨论】:

    • 嘿,这速度超级快!
    • 对于非平凡大小和/或大量密钥的文档,这可能是唯一实用的解决方案。 +1
    • @hek2mgl - 需要排序的 group_by 的使用对于大型数据集可能存在问题。此外,如果原始数据太大而无法放入内存,则需要一个初步步骤(例如使用 jq 的流解析器)。
    • 是的,我了解到here 时确实如此。我会记住这一点(在许多其他线程旁边:))
    【解决方案2】:

    你可以使用一个小的 shell 循环:

    #!/bin/bash
    jq -r '.[].symbol' stockprices.json | while read -r symbol ; do
        jq --arg s "${symbol}" \
            'map(if .symbol == $s then . else empty end)' \
        stockprices.json > "${symbol}".json
    done 
    

    【讨论】:

    • 谢谢,这很快!我现在正在运行你的脚本,我会反馈结果!
    • 好的。确保不要在 \ 字符后放置任何空格。这些是为了更好的可读性而进行的续行。它们必须直接出现在换行符的前面
    • 现在正在输出。它工作得很好。谢谢你的回答。
    【解决方案3】:

    这是一个一次性解决方案,假设您的 RAM 足够大。该解决方案避免使用group_by,因为这需要进行排序操作,这在时间和内存方面是不必要的并且可能成本高昂。

    为了创建输出文件,这里使用awk 是为了提高效率,但对方法来说并不重要。

    split.jq

    def aggregate_by(s; f; g):
      reduce s as $x  (null; .[$x|f] += [$x|g]);
    
    aggregate_by(.[]; .symbol; .)
    | keys_unsorted[] as $k
    | $k, .[$k]
    

    使用 awk 调用

    jq -f split.jq stockprices.json | awk '
      substr($0,1,1) == "\"" {
        if (fn) {close(fn)};
        gsub(/^"|"$/,"",$0); fn=$0 ".json"; next;
      }
      {print >> fn}'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-17
      • 2013-03-26
      • 1970-01-01
      相关资源
      最近更新 更多