본문으로 건너뛰기
jsonbeautifiers
한국어

JSON 필터

JSONPath 필터 표현식으로 필요한 부분만 뽑아냅니다.

문서
결과

붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기

JSONPath 필터 표현식으로 큰 문서를 필요한 부분만 남깁니다. 결과는 일치한 값들의 JSON 배열로 돌아오며, 그대로 복사할 수 있습니다.

이게 무엇인지 분명히 해 두자면, 이건 JSONPath이지 jq가 아닙니다. jq는 완전한 언어이고 복잡한 변환에는 진짜로 더 나은 도구입니다. 이 도구는 선택을 위한 것이고, 사실 대부분의 "필터링"은 선택입니다.

필터 표현식

매번 다시 찾아보게 되는 부분이라 문법을 한자리에 모았습니다.

$.items[?@.active]
키가 있고 참인 모든 항목. 존재 여부만으로도 유효한 조건입니다.
$.items[?@.price < 10]
숫자 비교. 크기 비교는 숫자끼리 또는 문자열끼리만 적용됩니다.
$.items[?@.type == 'book']
문자열 비교. 리터럴에는 따옴표가 필요하고, 여기가 가장 흔한 실수 지점입니다.
$.items[?@.price < 10 && @.stock > 0]
&&로 논리곱, ||로 논리합, 괄호로 묶습니다.
$.items[?!@.archived]
부정. 여기서는 키가 없거나 거짓이라는 뜻입니다.
$.items[?length(@.tags) > 2]
함수 확장. length()는 문자열, 배열, 객체에 쓸 수 있습니다.
$.items[?match(@.sku, '[A-Z]{3}-[0-9]+')]
값 전체에 앵커되는 정규식. 부분 일치에는 search()를 쓰세요.
$..[?@.id == 42]
모든 깊이에 적용되는 필터. 어디 있는지 모르는 레코드를 찾을 때 쓰는 방식입니다.

없는 키는 어떻게 되는가

RFC 이전 구현들이 가장 크게 갈라졌던 지점이라 짚어 둘 만합니다. RFC 9535에서 아무것도 고르지 않는 질의는 "없음"이고, 없는 값은 다른 없는 값과만 같습니다. 따라서 price가 없으면 @.price < 10은 거짓이 됩니다. 오류가 나지도, 일치하지도 않습니다. == 비교가 참이 되려면 양쪽 모두가 없어야 합니다.

실무적 결론: 부재를 확인하려면 @.price == null이 아니라 !@.price를 쓰세요. null은 값이고 부재는 값이 아니기 때문입니다.

How to do this in code

코드에서의 필터링. 대개는 jq가 정답인 영역입니다.

sh jq

세 번째 예제가 판단을 갈라놓는 줄입니다. 그룹화나 집계가 필요하면 jq를 쓰세요.

# Select, then reshape
jq '[.items[] | select(.price < 10) | {sku, price}]' data.json

# Filter at any depth
jq '[.. | objects | select(.id? == 42)]' data.json

# Group and aggregate, which JSONPath cannot do at all
jq 'group_by(.category) | map({category: .[0].category, n: length})' data.json
py Python
# A comprehension beats a query language for anything you
# can express directly.
cheap = [i for i in data['items'] if i['price'] < 10]

# JMESPath when the filter is configuration rather than code
import jmespath
cheap = jmespath.search("items[?price < `10`]", data)
js JavaScript
const cheap = data.items.filter((i) => i.price < 10);

// Deep search without a library
function findAll(node, test, out = []) {
  if (node && typeof node === 'object') {
    if (test(node)) out.push(node);
    for (const v of Object.values(node)) findAll(v, test, out);
  }
  return out;
}
const matches = findAll(data, (n) => n.id === 42);

자주 묻는 질문

왜 jq 플레이그라운드로 만들지 않았나요?
진짜 jq를 브라우저에서 돌리려면 WebAssembly로 컴파일한 것을 보내야 하고, 그건 대략 1메가바이트입니다. 빠르게 로드된다는 것이 논거인 사이트에서, 대부분이 변환이 아니라 선택에 쓰는 기능을 위해 그 값을 치르는 건 손해입니다. 게다가 JSONPath 필터를 jq 플레이그라운드라고 부르는 건 거짓말이고, 이 사이트는 그런 짓을 하지 않습니다.
필터링과 형태 변경을 동시에 할 수 있나요?
JSONPath로는 안 됩니다. 노드를 고를 뿐 새로 만들지는 않습니다. 멀티셀렉트 해시가 있는 JMESPath나 jq를 쓰세요.
문서 어디에 있든 특정 키를 가진 객체를 모두 찾으려면?
$..[?@.그키]가 모든 깊이에 필터를 적용합니다. 특정 레코드를 찾으려면 $..[?@.id == 42].