NDJSON Filter CLI
A Node CLI that reads newline-delimited JSON from stdin, keeps records matching a field selector, and writes NDJSON to stdout.
Project
node-ndjson-filter
Entry point: ndjson-filter.mjs
Install
node --versionRun
cat events.ndjson | node ndjson-filter.mjs level=errorTest
node --test ndjson.test.mjsExpected output
Writes only the records whose selected field equals the given value, one JSON object per line, preserving input order.Dependencies
- node >=20
What it does
Streams stdin line by line, parses each line as JSON, compares a dotted field path to the expected value, and writes matching records as NDJSON. A malformed line is reported to stderr and skipped so the stream continues.
import { createInterface } from 'node:readline';
const spec = process.argv[2];
if (!spec || !spec.includes('=')) { console.error('usage: ndjson-filter <field>=<value>'); process.exit(1); }
const [field, want] = spec.split('=', 2);
const value = want === 'true' ? true : want === 'false' ? false : want;
const get = (obj, path) => path.split('.').reduce((o, k) => (o == null ? o : o[k]), obj);
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
for await (const line of rl) {
if (!line.trim()) continue;
try {
const rec = JSON.parse(line);
if (get(rec, field) === value) process.stdout.write(JSON.stringify(rec) + '\n');
} catch {
process.stderr.write('skipping malformed line\n');
}
}
Run and verify
cat events.ndjson | node ndjson-filter.mjs level=error
Run the test command to check the implementation: node --test ndjson.test.mjs.
Expected Output
Given three events of which one has level “error”, the filtered stream contains only that line:
{"id":7,"level":"error","msg":"boom"}
Limitations
Equality only: no ranges or regular expressions. The field path supports dots but not array indexing, so values inside arrays must be flattened first.