我有一个复杂的JSON文件(〜8GB),其中包含企业的公开可用数据。我们已决定将文件分成多个CSV文件(或.xlsx中的选项卡),以便客户端可以轻松使用数据。这些文件将通过NZBN列/键进行链接。
我正在使用R和jsonlite读取一个小样本(在放大到整个文件之前)。我猜想我需要某种方式来指定每个文件中使用的键/列(即,第一个文件将具有标头:australianBusinessNumber,australianCompanyNumber,australianServiceAddress,第二个文件将具有标头:AnnualReturnFilingMonth,annualReturnLastFiled,countryOfOrigin ...)
以下是两个企业/实体的示例(我也捆绑了一些数据,因此忽略了实际值):test file
我几乎阅读了所有关于类似问题的文章,似乎都没有给我带来任何好运。我尝试了purrr,* apply命令,自定义展平函数和jqr(“ jq”的r版本-看起来很有希望,但我似乎无法运行)的变体。
这是尝试创建单独的文件,但是我不确定如何包括链接标识符(NZBN)+我一直遇到其他嵌套列表(我不确定有多少层嵌套)
bulk <- jsonlite::fromJSON("bd_test.json")
coreEntity <- data.frame(bulk$companies)
coreEntity <- coreEntity[,sapply(coreEntity, is.list)==FALSE]
company <- bulk$companies$entity$company
company <- purrr::reduce(company, dplyr::bind_rows)
shareholding <- company$shareholding
shareholding <- purrr::reduce(shareholding, dplyr::bind_rows)
shareAllocation <- shareholding$shareAllocation
shareAllocation <- purrr::reduce(shareAllocation, dplyr::bind_rows)
我不确定在展平/整理过程中拆分文件是否更容易,还是完全展平整个文件,以便每个业务/实体只有一行(然后根据需要收集列)-我不确定唯一需要担心的是,我需要将其扩展到约130万个节点(8GB JSON文件)。
理想情况下,我希望每次有新集合时都将csv文件拆分,并且该集合中的值将成为新csv / tab的列。
任何帮助或技巧都将不胜感激。
-------更新------
由于我的问题有点模糊而更新,我认为我只需要一些代码即可生成其中一个csv / tab,然后为其他集合进行复制。
例如,我想创建一个包含以下元素的csv:
我该怎么办?
答案 0 :(得分:0)
我不确定有多少层嵌套
这将非常有效地提供答案:
jq '
def max(s): reduce s as $s (null;
if . == null then $s elif $s > . then $s else . end);
max(paths|length)' input.json
(对于测试文件,答案是14。)
要获得数据的整体视图(架构),您可以 运行:
jq 'include "schema"; schema' input.json
其中{。{3}}处有schema.jq。这将产生一个结构模式。
除了标题以外,这是一个jq解决方案:
.companies.entity[]
| [.entityName, .nzbn]
+ (.emailAddress[] | [.uniqueIdentifier, .emailAddress, .emailPurpose, .emailPurposeDescription, .startDate])
| @csv
持股数据非常复杂,因此在下面,我使用了此页面其他地方定义的to_table
函数。
示例数据不包含“公司名称”字段,因此在下面,我添加了一个基于0的“公司索引”字段:
.companies.entity[]
| [.entityName, .nzbn] as $ix
| .company
| range(0;length) as $cix
| .[$cix]
| $ix + [$cix] + (.shareholding[] | to_table(false))
以上解决方案使用独立的jq可执行文件,但一切顺利,将相同的过滤器与gist一起使用应该是微不足道的,尽管要使用jq的include
,指定显式路径,例如:
include "schema" {search: "~/.jq"};
答案 1 :(得分:0)
如果输入的JSON足够规则,则您 可能会发现下面的展平函数很有用,特别是因为它可以基于输入的叶元素的“路径”以字符串数组的形式发出标头,该标头可以任意嵌套:
# to_table produces a flat array.
# If hdr == true, then ONLY emit a header line (in prettified form, i.e. as an array of strings);
# if hdr is an array, it should be the prettified form and is used to check consistency.
def to_table(hdr):
def prettify: map( (map(tostring)|join(":") ));
def composite: type == "object" or type == "array";
def check:
select(hdr|type == "array")
| if prettify == hdr then empty
else error("expected head is \(hdr) but imputed header is \(.)")
end ;
. as $in
| [paths(composite|not)] # the paths in array-of-array form
| if hdr==true then prettify
else check, map(. as $p | $in | getpath($p))
end;
例如,要为.emailAddress生成所需的表(不包含标题),可以编写:
.companies.entity[]
| [.entityName, .nzbn] as $ix
| $ix + (.emailAddress[] | to_table(false))
| @tsv
(添加标题并检查一致性, 现在暂时作为练习,但在下面进行处理。)
更有趣的是,您可以选择所需的级别,并自动生成多个表。有效地将输出分区到单独文件中的一种方法是使用awk。例如,您可以通过管道传输使用以下jq过滤器获得的输出:
["entityName", "nzbn"] as $common
| .companies.entity[]
| [.entityName, .nzbn] as $ix
| (to_entries[] | select(.value | type == "array") | .key) as $key
| ($ix + [$key] | join("-")) as $filename
| (.[$key][0]|to_table(true)) as $header
# First emit the line giving all the headers:
| $filename, ($common + $header | @tsv),
# Then emit the rows of the table:
(.[$key][]
| ($filename, ($ix + to_table(false) | @tsv)))
到
awk -F\\t 'fn {print >> fn; fn=0;next} {fn=$1".tsv"}'
这将在每个文件中产生标题;如果要进行一致性检查,请将to_table(false)
更改为to_table($header)
。