{"content":"# aux4/json\n\nJSON CLI tools with streaming, pagination, and high performance. Extract values by path, pretty-print or minify JSON, index and group arrays by fields, merge multiple files, paginate large datasets with token-level streaming, collect NDJSON streams into arrays, and count items -- all from the command line with zero dependencies.\n\n## Installation\n\n``bash\naux4 aux4 pkger install aux4/json\n`\n\n## Quick Start\n\n`bash\n# Extract a value by path\necho '{\"users\":[{\"name\":\"Alice\"}]}' | aux4 json get '$.users.0.name'\n\n# Pretty-print JSON\necho '{\"name\":\"Alice\",\"age\":30}' | aux4 json pretty\n\n# Minify JSON\ncat data.json | aux4 json inline\n\n# Count items in an array\ncat users.json | aux4 json count\n\n# Paginate a large array\ncat users.json | aux4 json page --offset 0 --limit 10\n\n# Merge multiple files by ID\naux4 json merge --id id users.json profiles.json\n\n# Collect NDJSON into a JSON array\ncat stream.ndjson | aux4 json collect\n`\n\n## Commands\n\n### aux4 json get\n\nExtract a value from JSON by path. Uses JSONPath syntax starting with $. Array elements are accessed by numeric index.\n\n`bash\necho '...' | aux4 json get <path>\n`\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| path | JSON path (e.g. $.users.0.name) | $ |\n\n#### Examples\n\n`bash\n# Get a nested field\necho '{\"user\":{\"name\":\"Alice\",\"email\":\"alice@example.com\"}}' | aux4 json get '$.user.name'\n# Output: Alice\n\n# Get an array element\necho '{\"items\":[\"a\",\"b\",\"c\"]}' | aux4 json get '$.items.1'\n# Output: b\n\n# Get the root object\ncat config.json | aux4 json get '$'\n`\n\n### aux4 json pretty\n\nPretty-print JSON with indentation. Reads JSON from stdin and outputs formatted JSON with 2-space indentation.\n\n`bash\necho '...' | aux4 json pretty\n`\n\n#### Examples\n\n`bash\necho '{\"name\":\"Alice\",\"age\":30}' | aux4 json pretty\n# Output:\n# {\n# \"name\": \"Alice\",\n# \"age\": 30\n# }\n`\n\n### aux4 json inline\n\nMinify JSON to a single line. Reads JSON from stdin and removes all unnecessary whitespace.\n\n`bash\ncat file.json | aux4 json inline\n`\n\n#### Examples\n\n`bash\n# Minify a pretty-printed file\ncat pretty.json | aux4 json inline\n# Output: {\"name\":\"Alice\",\"age\":30}\n\n# Pipe into another command\ncat config.json | aux4 json inline | aux4 curl request --method POST --header \"Content-Type: application/json\" https://api.example.com/config\n`\n\n### aux4 json index\n\nIndex a JSON array by one or more ID fields. Transforms an array of objects into an object keyed by the specified field values. When multiple ID fields are provided, the key is the values joined by a dash.\n\n`bash\ncat file.json | aux4 json index --id <fields>\n`\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| --id | ID field(s) separated by comma | required |\n\n#### Examples\n\n`bash\n# Index by a single field\necho '[{\"id\":1,\"name\":\"Alice\"},{\"id\":2,\"name\":\"Bob\"}]' | aux4 json index --id id\n# Output: {\"1\":{\"id\":1,\"name\":\"Alice\"},\"2\":{\"id\":2,\"name\":\"Bob\"}}\n\n# Index by composite key\necho '[{\"region\":\"us\",\"env\":\"prod\",\"url\":\"us.prod.example.com\"}]' | aux4 json index --id region,env\n# Output: {\"us-prod\":{\"region\":\"us\",\"env\":\"prod\",\"url\":\"us.prod.example.com\"}}\n`\n\n### aux4 json group\n\nGroup a JSON array by one or more ID fields. Objects sharing the same ID values are combined: the ID fields appear once, and all other fields are collected into arrays.\n\n`bash\ncat file.json | aux4 json group --id <fields>\n`\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| --id | ID field(s) separated by comma | required |\n\n#### Examples\n\n`bash\n# Group by department\necho '[{\"dept\":\"eng\",\"name\":\"Alice\"},{\"dept\":\"eng\",\"name\":\"Bob\"},{\"dept\":\"hr\",\"name\":\"Carol\"}]' | aux4 json group --id dept\n# Output: [{\"dept\":\"eng\",\"name\":[\"Alice\",\"Bob\"]},{\"dept\":\"hr\",\"name\":[\"Carol\"]}]\n`\n\n### aux4 json collect\n\nCollect an NDJSON (newline-delimited JSON) stream into a single JSON array. Each line of input is parsed as a JSON value and added to the output array.\n\n`bash\nprocess-that-streams | aux4 json collect\n`\n\n#### Examples\n\n`bash\n# Collect NDJSON into an array\nprintf '{\"id\":1}\\n{\"id\":2}\\n{\"id\":3}\\n' | aux4 json collect\n# Output: [{\"id\":1},{\"id\":2},{\"id\":3}]\n\n# Collect streaming output from another command\naux4 curl stream https://api.example.com/events | aux4 json collect > events.json\n`\n\n### aux4 json merge\n\nMerge multiple JSON files by one or more ID fields. Objects from different files with matching ID values are combined into a single object. Fields from later files overwrite earlier ones (except the ID fields which remain unchanged).\n\n`bash\naux4 json merge --id <fields> <file1> <file2> ...\n`\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| --id | ID field(s) separated by comma | required |\n| files | JSON files to merge (space-separated) | required |\n\n#### Examples\n\n`bash\n# Merge user data with profile data\n# users.json: [{\"id\":1,\"name\":\"Alice\"},{\"id\":2,\"name\":\"Bob\"}]\n# emails.json: [{\"id\":1,\"email\":\"alice@example.com\"},{\"id\":2,\"email\":\"bob@example.com\"}]\naux4 json merge --id id users.json emails.json\n# Output: [{\"id\":1,\"name\":\"Alice\",\"email\":\"alice@example.com\"},{\"id\":2,\"name\":\"Bob\",\"email\":\"bob@example.com\"}]\n\n# Merge with composite key\naux4 json merge --id region,env infra.json configs.json overrides.json\n`\n\n### aux4 json page\n\nPaginate a JSON array. Returns a slice of the array starting at --offset with up to --limit items. When --stream is true, outputs each item as a separate line (NDJSON) instead of a JSON array, enabling token-level streaming for large datasets.\n\n`bash\ncat file.json | aux4 json page [--offset N] [--limit M] [--stream true]\n`\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| --offset | Number of items to skip | 0 |\n| --limit | Number of items to return | 10 |\n| --stream | Output as NDJSON stream | false |\n\n#### Examples\n\n`bash\n# First page of 10 items\ncat users.json | aux4 json page --offset 0 --limit 10\n\n# Second page\ncat users.json | aux4 json page --offset 10 --limit 10\n\n# Stream mode for large datasets\ncat large-dataset.json | aux4 json page --offset 0 --limit 100 --stream true\n\n# Pipe streamed output for per-item processing\ncat users.json | aux4 json page --offset 0 --limit 50 --stream true | while read -r line; do echo \"$line\" | aux4 json get '$.name'; done\n`\n\n### aux4 json count\n\nCount the number of items in a JSON array. Reads a JSON array from stdin and outputs the count as a plain number.\n\n`bash\ncat file.json | aux4 json count\n`\n\n#### Examples\n\n`bash\n# Count items\necho '[{\"id\":1},{\"id\":2},{\"id\":3}]' | aux4 json count\n# Output: 3\n\n# Use in a script\ntotal=$(cat users.json | aux4 json count)\necho \"Total users: $total\"\n`\n\n### aux4 json exec\n\nRun a command for each record read from stdin. The input can be a JSON array or an NDJSON stream (one object per line), so exec consumes the output of any streaming command directly.\n\nEach record is exposed to the command through aux4's ${...} templating — the same convention as the core each: executor:\n\n- ${item} — the whole record, as JSON\n- ${item.field} — a field of the record (nested paths like ${item.user.name} work)\n- ${index} — the record's position, starting at 0\n\nThe raw record is also written to the command's stdin. By default exec stops at the first failing command; pass --ignoreErrors true to keep going.\n\n`bash\n... | aux4 json exec <command>\n`\n\n#### Examples\n\n`bash\n# Run a command per record\necho '[{\"file\":\"a.png\"},{\"file\":\"b.png\"}]' | aux4 json exec 'echo resized ${item.file}'\n# resized a.png\n# resized b.png\n\n# Consume a stream and dispatch a background job per record\naux4 queue receive --name resize | aux4 json exec 'aux4 jobs run \"echo resized ${item.file}\"'\n\n# Read the whole record from stdin instead of templating\ncat products.ndjson | aux4 json exec 'curl -X POST https://api.example.com/import -d @-'\n`\n\n### aux4 json select\n\nProject each record down to a chosen set of fields, keeping the result as JSON with types preserved. It is the JSON counterpart of aux4 2table and aux4 render — the same field notation that renders a table or a list here produces projected JSON:\n\n- name,age,city — keep these fields\n- address[city,country] — keep a nested object, selecting only its sub-fields\n- source:output — rename a field (source first, output second)\n- user.email — dot paths reach into nested objects\n- total{format:currency} — a trailing {...} display block is accepted but ignored, so specs are interchangeable with 2table/render\n\nMissing fields become null. With --inputStream true, select reads NDJSON and emits one projected object per line.\n\n`bash\n... | aux4 json select <structure>\n`\n\n#### Examples\n\n`bash\n# Keep a subset of fields (types preserved)\necho '[{\"id\":1,\"name\":\"Chai\",\"price\":18,\"note\":\"drop\"}]' | aux4 json select 'id,name,price'\n# [{\"id\":1,\"name\":\"Chai\",\"price\":18}]\n\n# Nested selection and renaming\necho '[{\"buyerName\":\"Sally\",\"address\":{\"city\":\"Austin\",\"country\":\"US\",\"zip\":\"78701\"}}]' \\\n | aux4 json select 'buyerName:customer,address[city,country]'\n# [{\"address\":{\"city\":\"Austin\",\"country\":\"US\"},\"customer\":\"Sally\"}]\n\n# Streaming projection (NDJSON in, NDJSON out)\naux4 mdb stream --file inventory.mdb --table Products \\\n | aux4 json select 'ProductName:name,UnitPrice:price' --inputStream true\n``\n\n## License\n\nApache-2.0\n"}