일부 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다른 키와 값이 있기 때문입니다.
  • 왜냐하면 thothTest나는 osirisTest아무것도 할 필요가 없기 때문입니다.

clientId각 키와 값에 대해 및 를 반복할 필요가 없도록 위의 json을 다시 디자인할 생각입니다 . 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(예: Python)을 이해하는 도구를 사용하여 수행하는 것이 가장 좋습니다 jq. 필요한 작업을 수행하는 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

내가 대답한 해결책은 기본적으로 다음과 같습니다.게시자: Sanasip이지만 도우미 함수를 사용하여 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" ]
   }
}

관련 정보