通过某种linux命令将巨大的旧json转换为新json格式?

通过某种linux命令将巨大的旧json转换为新json格式?

我有这样的原始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"
      ]
   }
}
  • clientSettingsjson 数组中,我们有clientId's它们的键/值。对于 single clientId,我可以有多个不同的键和值。例如 -12345 clientId具有不同的键和值,如上所示。
  • 同样地,对于productSettings也是如此。
  • 但因为customerSettings我只是有不同的键和值。
  • 因为thothTestosirisTest不需要做任何事情。

我正在考虑重新设计上面的 json,这样我就不必为每个键和值重复clientIdand 。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_bymap

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 的工具(例如jqPython)来完成。这是一个可以满足您需要的 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的内容进行分组和映射。clientSettingsproductSettings

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

没有要求以下内容,但由于多个数组包含“条目对象”(keyvalue),我们可以将所有这些都转换为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" ]
   }
}

相关内容