NDJSON은 Newline Delimited JSON 의 약어로, 각 줄마다 하나의 JSON 객체가 위치하는 텍스트 기반 데이터 포맷입니다. 일반 JSON 과 달리 NDJSON 은 큰 데이터셋이나 스트리밍 데이터를 다룰 때 유용하며, 한 번에 전체 데이터를 메모리에 적재하지 않고 한 줄 씩 처리할 수 있는 장점이 있습니다.
{"some":"thing"}
{"foo":170,"bar":false,"quux":true}
{"may":{"include":"nested","objects":["and","arrays"]}}
정말 이게 끝입니다! JSON Array 와 유사해 보이지만 처음과 끝에 대괄호가 없고 각 객체가 쉼표 대신 개행으로 구분 된다는 차이점이 있습니다.
NDJSON의 특징
행 단위의 데이터 처리
NDJSON 파일은 각 줄이 독립적인 JSON 객체로 구성되어 있기 때문에, 파일의 일부분만 읽어서 처리할 수 있습니다. 이러한 특성 덕분에 메모리를 효율적으로 사용하여 대용량 데이터 처리나 스트리밍 처리에 유리합니다.
또한 UNIX Pipes 와 궁합도 좋습니다. 마지막 로그를 보려면 어디까지 불러와야 하나 고민 되셨죠?
tail -n 1 log.ndjson
끝났습니다.
간단한 파싱 구조
각 줄이 JSON 객체 이므로, 줄 단위로 읽어 JSON 파서를 통해 쉽게 객체로 변환할 수 있습니다. 이는 데이터의 직렬화/역직렬화 작업을 간편하게 만들어 줍니다. 단, 처리할 때 빈 줄이 있는 경우 라던가 전체 객체 중 일부만 파싱에 실패하는 등 예외 처리에 대한 고려가 필요합니다.
유연한 데이터 추가
JSON Array 와 달리 새로운 데이터 객체를 추가할 때 마다 파일 전체를 읽을 필요 없이 파일의 끝에 단순히 추가하면 되므로, 실시간 로그 기록이나 데이터 추가 작업에 매우 효율적 입니다. 마찬가지로 최근에 추가된 데이터를 조회하기도 쉽습니다.
// json
const data = fs.readFileSync('./log.json', 'utf8');
const json = JSON.parse(data);
json.push({ timestamp: new Date().toISOString() });
fs.writeFileSync('./log.json', JSON.stringify(json), 'utf8');
// ndjson
const newEntity = { timestamp: new Date().toISOString() }
fs.appendFileSync('./log.json', JSON.stringify(newEntity), 'utf8');
정리
NDJSON 은 대용량 데이터 처리, 스트리밍 및 로그 기록에 매우 유용한 데이터 포맷입니다. 각 줄이 독립적인 JSON 객체로 구성되어 있기 때문에, 데이터를 한 줄 씩 처리할 수 있는 유연성을 제공합니다.
참고 : NDJSON 공식 스펙