Awk

通過某種linux命令將巨大的舊json轉換成新的json格式?

  • October 14, 2021

我有這樣的原始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我只是有不同的鍵和值。
  • 因為thothTest而且osirisTest我不需要做任何事情。

我正在考慮重新設計上面的 json,這樣我就不必為每個鍵和值重複clientId和。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,那麼它可以加快這個過程。

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"
   ]
 }
}

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 或任何類似的文件數據庫,例如參見手冊中的這個map-reduce 頁面,這就是您現在正在做的,沒有 reduce部分。所有這些操作都可以比解析 json 文件更快,語法類似於簡單的 javascript。

引用自:https://unix.stackexchange.com/questions/612900