使用csv文件内容更新json文件



我有两个文件:changes.csv和sample.json。我的csv文件如下所示:

header "a", "b"
"a11","b1"
"a22","b2"
"a33","b3"

, json文件如下:

[
{"a":"a1","b":"b1"},
{"a":"a2","b":"b2"},
{"a":"a3","b":"b3"},
{"a":"a4","b":"b4"}
]

我需要写一个jq命令,它使用csv文件对json文件进行更改,即json文件的最终输出应该如下所示:

[
{"a":"a11","b":"b1"},
{"a":"a22","b":"b2"},
{"a":"a33","b":"b3"},
{"a":"a4","b":"b4"}
]

我写了下面的命令:

while IFS=",", read f1 f2
do
jq --argjson k1 $f1 --argjson k2 $f2 '(.[] | select(.b == $k2) | .a) |= $k1' sample.json| sponge sample.json
done < changes.csv

虽然,对于每次迭代,它都能够过滤和更新键"a"的值,但是当我试图将结果海绵到json文件中时,它无法这样做。我不知道我错过了什么。

假设CSV的行为相当良好,您可以这样写:

# Skip the CSV header row by NOT specifying the -n option
< changes.csv | jq -Rcr --argfile json sample.json '
def trim: sub("^[ t]*""; "") | sub(""[ t]*$";"");
INDEX(inputs | split(",") | map(trim) | select(length>0); .[1]) as $dict
| $json
| map( .a = $dict[.b][0] )
'

对于更混乱的CSV,您可能需要使用CSV-to- json或CSV-to- tsv工具(它们都可以很容易地用jq编写—例如参见https://rosettacode.org/wiki/Convert_CSV_records_to_TSV#jq)


如果你不喜欢使用——argfile选项,那么无论如何都可以使用其他方法读取这两个文件,例如,你可以使用——rawfile来读取CSV文件,留下STDIN来读取JSON文件。

对于纯jq解决方案,您最好确保您的CSV在任何字段中不包含任何,"n,否则代码将变得更加复杂。

因此,我用Miller提出了一个解决方案(可以在这里为几个操作系统提供),它可以轻松而健壮地完成任务:

mlr --icsv --ojson --no-jvstack join --ijson -f file.json -j 'b' --ul file.csv
[
{"b": "b1", "a": "a11"},
{"b": "b2", "a": "a22"},
{"b": "b3", "a": "a33"}
]

让我们分解命令:

  • mlr join -f file1 -j 'b' file2
    

    将在字段b上加入file1file2。当中存在b以外的其他字段时,文件(例如a),那么输出的是file2的值。
    因此,为了使用CSV中的值更新JSON,file1应为JSON,file2为CSV。

  • --ul表示输出file1不可连接的行;如果没有它,输出将只包含已"配对"的记录。

  • 使用join动词,Miller允许指定不同的输入格式对于file1,小于file2;您将默认输入格式设置为--icsv(用于处理file2),并在join谓词之后使用--ijson覆盖它(用于处理file1)。

  • 输出格式使用--ojson设置为JSON。--no-jvstack表示输出一条"记录"。每行.

如果我将csv文件值转换为可读输入格式并使用——arg而不是——argjson,文件就会得到更新。因此,命令awk '{gsub(/"/,"")};1' b.csv > c.csv将把csv文件转换为:

a11,b1
a22,b2
a33,b3

那么,现在如果应用命令:

while IFS=",", read f1 f2
do
jq --arg k1 $f1 --arg k2 $f2 '(.[] | select(.b == $k2) | .a) |= $k1' sample.json| sponge sample.json
done < c.csv

期望的变化将发生。

在旧格式中失败的合理原因是当我们使用"read"读取值时命令,将"a"转换为""a""。因此,每次我附加答案时,它都会返回空答案。

答案适用于任何类型的json格式。例如,如果json对象如下:

[
{ 
"d": { "a":"a1", "c":"c1"},
"b": "b1"
}
]

我们可以将命令更新为'(.[] | select(.b == $k2) | .d.a) |= $k1'

我没有尝试其他方法张贴,但我感谢你的帮助。谢谢大家(@peak &@Fravadona)

相关内容

  • 没有找到相关文章

最新更新