我有这样的原始json。一般来说,我的json很大。为了让事情变得更简单、更容易理解,我减少了条目。
{
"clientSettings":[
{
"clientId":12345,
"key":"abc",
"value":false
},
{
"clientId":12345,
"key":"def",
"value":false
},
{
"clientId":12345,
"key":"ghi",
"value":false
},
{
"clientId":9876,
"key":"lkmn",
"value":false
}
],
"productSettings":[
{
"productId":11,
"key":"jkl",
"value":true
},
{
"productId":11,
"key":"mno",
"value":true
},
{
"productId":12,
"key":"jkl",
"value":true
},
{
"productId":12,
"key":"mno",
"value":true
}
],
"customerSettings":[
{
"key":"enableData",
"value":false
},
{
"key":"minPriceValue",
"value":"1.0"
},
{
"key":"presentData",
"value":"AEGIS"
}
],
"thothTest":{
"9876":[
"K"
],
"5431":[
"A",
"L"
],
"5123":[
"L"
]
},
"osirisTest":{
"7678":[
"K"
]
}
}
- 在
clientSettings
json 数组中,我们有clientId's
它们的键/值。对于 singleclientId
,我可以有多个不同的键和值。例如 -12345
clientId
具有不同的键和值,如上所示。 - 同样地,对于
productSettings
也是如此。 - 但因为
customerSettings
我只是有不同的键和值。 - 因为
thothTest
我osirisTest
不需要做任何事情。
我正在考虑重新设计上面的 json,这样我就不必为每个键和值重复clientId
and 。productId
到目前为止,我的 json 很大,因为我有很多ids
相同的,但具有不同的键和值。
所以我想出了下面的新 json 设计,它可以代表上面的 json -
{
"clientSettings":[
{
"clientId":12345,
"entries":[
{
"key":"abc",
"value":false
},
{
"key":"def",
"value":false
},
{
"key":"ghi",
"value":false
}
]
},
{
"clientId":9876,
"entries":[
{
"key":"lkmn",
"value":false
}
]
}
],
"productSettings":[
{
"productId":11,
"entries":[
{
"key":"jkl",
"value":true
},
{
"key":"mno",
"value":true
}
]
},
{
"productId":12,
"entries":[
{
"key":"jkl",
"value":true
},
{
"key":"mno",
"value":true
}
]
}
],
"customerSettings":[
{
"key":"enableData",
"value":false
},
{
"key":"minPriceValue",
"value":"10.28"
},
{
"key":"presentData",
"value":"AEGIS"
}
],
"thothTest":{
"9876":[
"K"
],
"5431":[
"A",
"L"
],
"5123":[
"L"
]
},
"osirisTest":{
"7678":[
"K"
]
}
}
问题陈述
现在给定一个旧的 json - 有没有办法通过某种脚本或 Linux 命令将其转换为新的 json 格式?由于我的 json 非常大,所以对每个 id 进行一一处理会花费一些时间,所以我们在想,如果我们可以通过一些 Linux 命令将我的旧 json 转换为新 json,那么它可以加快该过程。
答案1
jq
您可以使用多种不同的方式重塑 JSON 。一种方法是分组依据.clientId
,并映射到一个新对象,该对象.clientId
将位于分组数组之外。使用group_by
和map
:
jq ' .clientSettings |=
( group_by(.clientId) |
map( {clientId: .[0].clientId, entries: del(.[].clientId)} )
) |
.productSettings |=
( group_by(.productId) |
map( {productId: .[0].productId, entries: del(.[].productId)} )
) ' file.json
我刚刚为第二个对象复制粘贴了相同的命令。
如果您需要经常对大型 JSON 进行操作,我建议您熟悉并使用 mongodb 或任何类似的文档数据库,例如参见此地图缩小页面从手册来看,这就是您现在正在做的事情,没有减少部分。所有这些操作都比解析 json 文件更快,语法类似于简单的 javascript。
答案2
JSON 处理最好使用理解 JSON 的工具(例如jq
Python)来完成。这是一个可以满足您需要的 Python 脚本:
#! /usr/bin/env python3
import json
import sys
from collections import defaultdict
def combine(data, key, id_key):
new_settings = defaultdict(list)
for setting in data[key]:
# Remove the ID from the setting and add it to the list of settings for that ID
new_settings[setting.pop(id_key)].append(setting)
# arrange the new settings in the desired format and overwrite the old settings
data[key] = [{id_key: key, "entries": values} for key, values in new_settings.items()]
data = json.load(sys.stdin)
combine(data, "clientSettings", "clientId")
combine(data, "productSettings", "productId")
print(json.dumps(data))
将 JSON 输入到标准输入并使用输出:
$ ./process.py < old.json | jq
{
"clientSettings": [
{
"clientId": 12345,
"entries": [
{
"key": "abc",
"value": false
},
{
"key": "def",
"value": false
},
{
"key": "ghi",
"value": false
}
]
},
{
"clientId": 9876,
"entries": [
{
"key": "lkmn",
"value": false
}
]
}
],
"productSettings": [
{
"productId": 11,
"entries": [
{
"key": "jkl",
"value": true
},
{
"key": "mno",
"value": true
}
]
},
{
"productId": 12,
"entries": [
{
"key": "jkl",
"value": true
},
{
"key": "mno",
"value": true
}
]
}
],
"customerSettings": [
{
"key": "enableData",
"value": false
},
{
"key": "minPriceValue",
"value": "1.0"
},
{
"key": "presentData",
"value": "AEGIS"
}
],
"thothTest": {
"9876": [
"K"
],
"5431": [
"A",
"L"
],
"5123": [
"L"
]
},
"osirisTest": {
"7678": [
"K"
]
}
}
答案3
我所回答的解决方案基本上与萨纳西普 发布,但重新编写为使用辅助函数 ,来对和数组groupmap
的内容进行分组和映射。clientSettings
productSettings
def groupmap($key):
group_by(.[$key]) |
map( { ($key): first[$key], entries: map(del(.[$key])) } );
.clientSettings |= groupmap("clientId") |
.productSettings |= groupmap("productId")
有了这个script
,您将使用以下命令运行它
jq -f script file.json
没有要求以下内容,但由于多个数组包含“条目对象”(key
和value
),我们可以将所有这些都转换为key: value
条目:
def groupmap($key):
group_by(.[$key]) |
map( { ($key): first[$key], entries: map(del(.[$key])) } );
.clientSettings |= (groupmap("clientId") | map(.entries |= from_entries)) |
.productSettings |= (groupmap("productId") | map(.entries |= from_entries)) |
.customerSettings |= from_entries
经过这些修改,您的结果现在将如下所示:
{
"clientSettings": [
{
"clientId": 9876,
"entries": { "lkmn": false }
},
{
"clientId": 12345,
"entries": { "abc": false, "def": false, "ghi": false }
}
],
"customerSettings": { "enableData": false, "minPriceValue": "1.0", "presentData": "AEGIS" },
"osirisTest": {
"7678": [ "K" ]
},
"productSettings": [
{
"entries": { "jkl": true, "mno": true },
"productId": 11
},
{
"entries": { "jkl": true, "mno": true },
"productId": 12
}
],
"thothTest": {
"5123": [ "L" ],
"5431": [ "A", "L" ],
"9876": [ "K" ]
}
}