json - 流式传输而不截断
问题描述
我有以下形式的 json 数据。我想对其进行转换,以流方式将每条记录的键转换为该记录的字段。我的问题:如果不截断密钥并丢失它,我不知道该怎么做。我已经推断出所需的流结构,见底部。
问题:如何在不丢失密钥的情况下将输入数据转换为流?
数据:
{
"foo" : {
"a" : 1,
"b" : 2
},
"bar" : {
"a" : 1,
"b" : 2
}
}
非流式转换使用:
jq 'with_entries(.value += {key}) | .[]'
产生:
{
"a": 1,
"b": 2,
"key": "foo"
}
{
"a": 1,
"b": 2,
"key": "bar"
}
现在,如果我的数据文件非常大,我更喜欢流式传输:
jq -ncr --stream 'fromstream(1|truncate_stream(inputs))`
问题:这会截断键"foo"
和"bar"
. 另一方面,不截断流而只调用fromstream(inputs)
是毫无意义的:这使得整个--stream
部分成为空操作并将jq
所有内容读入内存。
流的结构如下,使用. | tostream
:
[
[
"foo",
"a"
],
1
]
[
[
"foo",
"b"
],
2
]
[
[
"foo",
"b"
]
]
[
[
"bar",
"a"
],
1
]
[
[
"bar",
"b"
],
2
]
[
[
"bar",
"b"
]
]
[
[
"bar"
]
]
而使用截断, . as $dot | (1|truncate_stream($dot | tostream))
, 结构是:
[
[
"a"
],
1
]
[
[
"b"
],
2
]
[
[
"b"
]
]
[
[
"a"
],
1
]
[
[
"b"
],
2
]
[
[
"b"
]
]
所以看起来为了让我按照我需要的方式构造一个流,我必须生成以下结构(我[["foo"]]
在第一条记录完成后插入了一个):
[
[
"foo",
"a"
],
1
]
[
[
"foo",
"b"
],
2
]
[
[
"foo",
"b"
]
]
[
[
"foo"
]
]
[
[
"bar",
"a"
],
1
]
[
[
"bar",
"b"
],
2
]
[
[
"bar",
"b"
]
]
[
[
"bar"
]
]
把它变成一个字符串jq
可以消耗,我确实得到了我需要的东西(另见这里的片段:https ://jqplay.org/s/iEkMfm_u92 ):
fromstream([ [ "foo", "a" ], 1 ],[ [ "foo", "b" ], 2 ],[ [ "foo", "b" ] ],[["foo"]],[ [ "bar", "a" ], 1 ],[ [ "bar", "b" ], 2 ],[ [ "bar", "b" ] ],[ [ "bar" ] ])
产生:
{
"foo": {
"a": 1,
"b": 2
}
}
{
"bar": {
"a": 1,
"b": 2
}
}
最终结果(参见https://jqplay.org/s/-UgbEC4BN8)将是:
fromstream([ [ "foo", "a" ], 1 ],[ [ "foo", "b" ], 2 ],[ [ "foo", "b" ] ],[["foo"]],[ [ "bar", "a" ], 1 ],[ [ "bar", "b" ], 2 ],[ [ "bar", "b" ] ],[ [ "bar" ] ]) | with_entries(.value += {key}) | .[]
屈服
{
"a": 1,
"b": 2,
"key": "foo"
}
{
"a": 1,
"b": 2,
"key": "bar"
}
解决方案
jq Cookbook中提供了一个通用函数,atomize(s)
用于将对象转换为键值对象。使用它,这里问题的解决方案很简单:
atomize(inputs) | to_entries[] | .value + {key}
({key}
是 的简写{key: .key}
。)
作为参考,这里是def
:
雾化
# Convert an object (presented in streaming form as the stream s) into
# a stream of single-key objects
# Example:
# atomize(inputs) (used in conjunction with "jq -n --stream")
def atomize(s):
fromstream(foreach s as $in ( {previous:null, emit: null};
if ($in | length == 2) and ($in|.[0][0]) != .previous and .previous != null
then {emit: [[.previous]], previous: ($in|.[0][0])}
else { previous: ($in|.[0][0]), emit: null}
end;
(.emit // empty), $in
) ) ;
推荐阅读
- eclipse - 在 Eclipse RCPTT 中使用 foreach 或 regex 进行验证
- php - 使用 if 语句无效使用组函数
- django - 如何向 Django Admin 添加 url 前缀?
- wordpress - 如何在wordpress function.php中编写条件语句
- windows - IIS 重命名图像仍显示以前的内容 - 缓存问题?
- javascript - 无法让 setValue 在 Dynamics CRM 可编辑网格上工作
- html - 为什么我的悬停样式没有被应用?
- asynchronous - 如何在grails3中休息响应后继续异步任务
- nopcommerce-3.90 - www 前缀在 NOPCommerce 上不起作用
- xaml - Xamarian 表单预览错误