JSON 평탄화
중첩된 JSON을 한 단계 키 경로로 바꾸고, 다시 되돌릴 수도 있습니다.
붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기
평탄화는 중첩된 문서를 점으로 이어진 한 단계 경로로 바꿉니다. {"a":{"b":1}}은 {"a.b":1}이 됩니다. 되돌리면 원래대로 돌아옵니다.
JSON을 뭔가 네모난 것에 싣기 전에 하는 일입니다. 스프레드시트, 데이터 프레임, 기능 플래그 저장소, 환경 파일, 폼 같은 것들이요.
왕복, 그리고 그것을 깨뜨리는 유일한 경우
평탄화했다가 되돌리면 원래 문서가 그대로 돌아옵니다. 여러 구현이 조용히 버리는 빈 객체와 빈 배열까지 포함해서요.
불가능한 경우는 딱 하나입니다. 키 자체에 구분자가 들어 있는 경우입니다. {"a.b": 1}을 평탄화한 경로 "a.b"는 중첩된 {"a":{"b":1}}과 구별되지 않습니다. 이 도구는 그걸 감지해서 경고합니다. 되돌릴 수 없는 결과를 조용히 만들지 않습니다. 그럴 때는 다른 구분자를 고르세요.
배열: 인덱스 표기냐 대괄호 표기냐
점 표기는 tags.0, tags.1을 만듭니다. 대괄호 표기는 tags[0], tags[1]을 만듭니다. 여기서는 둘 다 왕복이 되고, 입력 파서도 둘 다 받아들입니다.
점 표기는 pandas의 json_normalize가 만들어 내는 형태이고 대부분의 CSV 파이프라인이 기대하는 형태입니다. 대괄호 표기는 키가 숫자일 법한 상황에서 더 읽기 좋습니다. tags[0]과 tags.0은 모호하지만 tags["0"]은 그렇지 않기 때문입니다.
평탄화가 정보를 잃는 지점
숫자로 된 객체 키는 평탄화하고 나면 배열 인덱스와 구별되지 않습니다. {"2024": {"total": 1}}은 "2024.total"이 되고, 배열 감지를 켠 채 되돌리면 빈 자리가 2024개인 배열이 만들어집니다.
키가 정말로 숫자 문자열이라면 "숫자 키를 배열로" 옵션을 끄세요. 연도, HTTP 상태 코드, ID를 키로 쓰는 데이터에서 흔한 경우입니다.
How to do this in code
코드에서의 평탄화.
py Python, pandas
record_path는 일대다 관계를 번호가 붙은 열이 아니라 행으로 펼쳐 주는 인자입니다.
import pandas as pd
# The workhorse. sep defaults to '.'
df = pd.json_normalize(records)
# Explode a nested array into one row per element
df = pd.json_normalize(
records,
record_path='items',
meta=['id', 'created_at'],
) sh jq
# Every leaf as a dotted path
jq -r 'paths(scalars) as $p | "\($p | join(".")) = \(getpath($p))"' in.json
# A flat object rather than lines
jq '[leaf_paths as $p | {(($p | map(tostring) | join("."))): getpath($p)}] | add' in.json js JavaScript
빈 컨테이너를 다루는 분기가 바로 대부분의 구현이 빠뜨리는 줄이고, 그래서 그것들은 왕복이 되지 않습니다.
function flatten(value, prefix = '', out = {}) {
if (value && typeof value === 'object') {
const entries = Array.isArray(value)
? value.map((v, i) => [i, v])
: Object.entries(value);
if (entries.length === 0) {
out[prefix] = value; // preserve {} and []
return out;
}
for (const [k, v] of entries) {
flatten(v, prefix ? `${prefix}.${k}` : String(k), out);
}
return out;
}
out[prefix] = value;
return out;
} 자주 묻는 질문
- 어떤 구분자를 써야 하나요?
- 키에 점이 들어 있지 않다면 점을 쓰세요. 흔한 두 번째 선택은 밑줄이고, 결과가 이미 경로로 생각하는 곳으로 간다면 슬래시가 유용합니다.
- 문서의 일부만 평탄화할 수 있나요?
- 깊이 제한을 두세요. 그보다 깊은 부분은 중첩된 값 그대로 남습니다. 깊은 쪽이 조회하지 않고 저장만 하는 불투명한 덩어리일 때 딱 맞는 동작입니다.
- null은 어떻게 되나요?
- 기본적으로 값이 null인 평탄화된 키로 유지됩니다. null을 빼는 옵션도 있는데, diff에는 유용하고 왕복에는 위험합니다.