{"id":26107082,"url":"https://github.com/duriantaco/jonq","last_synced_at":"2026-04-29T15:00:59.050Z","repository":{"id":281419956,"uuid":"945239995","full_name":"duriantaco/jonq","owner":"duriantaco","description":"Query JSON with SQL-like syntax. A readable jq alternative that generates pure jq under the hood. Table, CSV, YAML output. Interactive REPL. Pipes from curl, streams NDJSON logs.","archived":false,"fork":false,"pushed_at":"2026-04-29T05:24:56.000Z","size":2737,"stargazers_count":43,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-04-29T07:13:12.921Z","etag":null,"topics":["cli","command-line-tools","csv","data-extraction","jq","jq-alternative","json","json-parser","json-processor","json-query","log-analysis","ndjson","python","sql","yaml"],"latest_commit_sha":null,"homepage":"https://jonq.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/duriantaco.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"License","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-09T01:05:19.000Z","updated_at":"2026-04-29T05:24:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"787d96b1-cd3f-46de-a354-c3140a0e4c3a","html_url":"https://github.com/duriantaco/jonq","commit_stats":null,"previous_names":["duriantaco/jonq"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/duriantaco/jonq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fjonq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fjonq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fjonq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fjonq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/duriantaco","download_url":"https://codeload.github.com/duriantaco/jonq/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fjonq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32430803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T13:34:34.882Z","status":"ssl_error","status_checked_at":"2026-04-29T13:34:29.830Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line-tools","csv","data-extraction","jq","jq-alternative","json","json-parser","json-processor","json-query","log-analysis","ndjson","python","sql","yaml"],"created_at":"2025-03-09T22:43:10.543Z","updated_at":"2026-04-29T15:00:59.042Z","avatar_url":"https://github.com/duriantaco.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"docs/source/_static/jonq.png\" alt=\"jonq - SQL-like JSON query tool for the command line\" width=\"200\"/\u003e\n\n# jonq - readable JSON queries for the terminal\n\n### A jq-powered CLI for inspecting, filtering, and reshaping JSON without writing raw jq\n\n[![PyPI version](https://img.shields.io/pypi/v/jonq.svg)](https://pypi.org/project/jonq/)\n[![Python Versions](https://img.shields.io/pypi/pyversions/jonq.svg)](https://pypi.org/project/jonq/)\n[![CI tests](https://github.com/duriantaco/jonq/actions/workflows/tests.yml/badge.svg)](https://github.com/duriantaco/jonq/actions)\n[![Documentation Status](https://readthedocs.org/projects/jonq/badge/?version=latest)](https://jonq.readthedocs.io)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](License)\n[![Skylos Grade](https://img.shields.io/badge/Skylos-A%2B%20%28100%29-brightgreen)](https://github.com/duriantaco/skylos)\n\u003c/div\u003e\n\n---\n\n## What jonq is\n\n`jonq` is a command-line JSON query tool. It lets you write readable, SQL-like queries such as:\n\n```bash\njonq users.json \"select name, age if age \u003e 30\" -t\n```\n\nInstead of raw jq:\n\n```bash\njq '.[] | select(.age \u003e 30) | {name, age}' users.json\n```\n\njonq compiles your query to jq and executes it with a reusable jq worker. It is useful when you need to understand an unfamiliar JSON payload, extract fields, filter rows, flatten nested arrays, or turn JSON into table, CSV, JSONL, YAML, or raw scalar output.\n\n\u003e jonq is not a database, ETL framework, or analytics engine. It is a JSON exploration and shaping tool for terminal workflows.\n\n## When to use it\n\nUse jonq when you need to:\n\n- inspect an API response, config file, generated JSON, or log payload\n- select and rename fields without remembering jq object syntax\n- filter JSON with readable conditions\n- query nested objects and arrays\n- produce table, CSV, JSONL, YAML, raw scalar, or compact JSON output\n- run the same query in shell scripts, CI, or Python code\n- follow NDJSON logs line-by-line\n\nUse another tool when you need:\n\n- exact jq language control: use raw `jq`\n- Python expressions over JSON: use [`jello`](https://github.com/kellyjonbrazil/jello)\n- grep-friendly flattened assignment lines: use [`gron`](https://github.com/tomnomnom/gron)\n- joins, window functions, or relational analytics: use a database or analytics engine\n- production ETL, scheduling, or connectors: use an ETL system\n\n## Install\n\njonq requires Python 3.9+ and the `jq` command-line tool.\n\n```bash\npip install jonq\n```\n\nFrom source:\n\n```bash\ngit clone https://github.com/duriantaco/jonq.git\ncd jonq\npip install -e .\n```\n\nCheck that `jq` is available:\n\n```bash\njq --version\n```\n\n## Quick Start\n\nCreate a sample file:\n\n```bash\ncat \u003e users.json \u003c\u003c'JSON'\n[\n  {\"id\": 1, \"name\": \"Alice\", \"age\": 30, \"city\": \"New York\"},\n  {\"id\": 2, \"name\": \"Bob\", \"age\": 25, \"city\": \"Los Angeles\"},\n  {\"id\": 3, \"name\": \"Charlie\", \"age\": 35, \"city\": \"Chicago\"}\n]\nJSON\n```\n\nSelect fields:\n\n```bash\njonq users.json \"select name, age\"\n```\n\nFilter rows:\n\n```bash\njonq users.json \"select name, age if age \u003e 30\"\n```\n\nPrint raw values for shell pipelines:\n\n```bash\njonq users.json \"select name\" -r\n```\n\nRender a table:\n\n```bash\njonq users.json \"select name, city, age sort age desc\" -t\n```\n\nGet unique values:\n\n```bash\njonq users.json \"select distinct city\"\n```\n\nAggregate:\n\n```bash\njonq users.json \"select count(*) as total, avg(age) as avg_age\"\n```\n\nSee what jq will run:\n\n```bash\njonq users.json \"select name if age \u003e 30\" --explain\n```\n\n## Query Syntax\n\n```text\nselect [distinct] \u003cfields\u003e\n  [from \u003cpath\u003e]\n  [if|where \u003ccondition\u003e]\n  [group by \u003cfields\u003e [having \u003ccondition\u003e]]\n  [sort \u003cfield\u003e [asc|desc]]\n  [limit N]\n```\n\nExamples:\n\n```bash\njonq users.json \"select *\"\njonq users.json \"select name as full_name, age\"\njonq users.json \"select name if city in ('New York', 'Chicago')\"\njonq users.json \"select name where age \u003e 30\"\njonq users.json \"select name if not age \u003e 30\"\njonq users.json \"select name if name like 'Al%'\"\njonq users.json \"select name if age between 25 and 35\"\njonq users.json \"select city, count(*) as count group by city\"\njonq users.json \"select city, avg(age) as avg_age group by city having avg_age \u003e 30\"\njonq users.json \"select name, age sort age desc limit 2\"\n```\n\n## Fields and Expressions\n\nSelect nested fields with dot notation:\n\n```bash\njonq users.json \"select profile.email, profile.address.city\"\n```\n\nSelect from nested arrays with `from`:\n\n```bash\njonq orders.json \"select id, total from orders\"\njonq users.json \"select order_id, price from [].orders if price \u003e 100\"\n```\n\nUse array indexes:\n\n```bash\njonq users.json \"select name, orders[0].item as first_order\"\n```\n\nUse functions and expressions:\n\n```bash\njonq users.json \"select upper(name) as name, str(age) as age\"\njonq users.json \"select name || ' (' || city || ')' as label\"\njonq users.json \"select age * 2 + 3 as score\"\njonq users.json \"select coalesce(nickname, name) as display\"\njonq users.json \"select case when age \u003e 30 then 'senior' else 'junior' end as segment\"\n```\n\nCommon functions:\n\n| Category | Functions |\n|----------|-----------|\n| Strings | `upper`, `lower`, `length`, `trim`, `ltrim`, `rtrim` |\n| Math | `round`, `abs`, `ceil`, `floor` |\n| Casting | `int`, `float`, `str`, `string`, `type` |\n| Dates | `todate`, `fromdate`, `date`, `timestamp` |\n| JSON/arrays | `keys`, `values`, `tojson`, `fromjson`, `reverse`, `sort`, `unique`, `flatten` |\n| Nulls | `coalesce`, `is null`, `is not null` |\n\n## Output Formats\n\nJSON is the default:\n\n```bash\njonq users.json \"select name, age\"\n```\n\nTable:\n\n```bash\njonq users.json \"select name, age, city\" -t\njonq users.json \"select name, age, city\" --format table\n```\n\nCSV:\n\n```bash\njonq users.json \"select name, age\" --format csv \u003e users.csv\n```\n\nJSONL:\n\n```bash\njonq users.json \"select name, age\" --format jsonl \u003e users.jsonl\n```\n\nYAML:\n\n```bash\njonq users.json \"select name, age\" --format yaml\n```\n\nRaw scalar values:\n\n```bash\njonq users.json \"select name\" -r\n```\n\n## Input Sources\n\nLocal file:\n\n```bash\njonq data.json \"select id, name\"\n```\n\nPiped stdin:\n\n```bash\ncurl -s https://api.example.com/users | jonq \"select id, name\" -t\ncat data.json | jonq \"select id, name where active = true\"\ncat data.json | jonq - \"select id, name\"\n```\n\nURL:\n\n```bash\njonq https://api.example.com/users.json \"select id, email\"\n```\n\nGlob:\n\n```bash\njonq 'logs/*.json' \"select * if level = 'error'\"\n```\n\nNDJSON file:\n\n```bash\njonq app.ndjson \"select level, message if level = 'error'\"\n```\n\nFollow live NDJSON from stdin:\n\n```bash\ntail -f app.ndjson | jonq --follow \"select level, message if level = 'error'\" -t\n```\n\n## Inspect Before Querying\n\nRun jonq with no query to inspect paths, inferred types, sample values, and a suggested query:\n\n```bash\njonq data.json\n```\n\nExample output:\n\n```text\ndata.json  (array, sampled 3 items)\n\nPaths:\n  id    int  1\n  name  str  \"Alice\"\n  age   int  30\n  city  str  \"New York\"\n\nSample:\n  {\n    \"id\": 1,\n    \"name\": \"Alice\",\n    \"age\": 30,\n    \"city\": \"New York\"\n  }\n\nTip: jonq data.json \"select id, name\"\n```\n\n## Streaming and Watch Modes\n\nStreaming mode processes root-array JSON in chunks:\n\n```bash\njonq large.json \"select id, name if active = true\" --stream\n```\n\nStreaming is for row-wise queries. It intentionally rejects queries that require global input state, including `group by`, `sort`, `distinct`, `limit`, `count`, `sum`, `avg`, `min`, `max`, and `count(distinct ...)`.\n\nWatch mode reruns a query when a file changes:\n\n```bash\njonq data.json \"select name, age\" --watch\n```\n\nInteractive mode provides history and field-aware completion:\n\n```bash\njonq -i data.json\n```\n\n## Python API\n\nUse `query(...)` when you want Python data back:\n\n```python\nfrom jonq import query\n\ndata = [\n    {\"name\": \"Alice\", \"age\": 30},\n    {\"name\": \"Bob\", \"age\": 25},\n]\n\nrows = query(data, \"select name if age \u003e 26\")\nprint(rows)\n```\n\nUse `execute(...)` when you want text output plus metadata:\n\n```python\nfrom jonq import execute\n\nresult = execute(data, \"select name, age\", format=\"jsonl\")\nprint(result.text)\nprint(result.compiled.jq_filter)\n```\n\nCompile once and reuse:\n\n```python\nfrom jonq import compile_query, query\n\ncompiled = compile_query(\"select name if age \u003e 25\")\nprint(query([{\"name\": \"Alice\", \"age\": 30}], compiled))\n```\n\nAsync helpers are also available: `query_async(...)` and `execute_async(...)`.\n\n## CLI Options\n\n| Option | Description |\n|--------|-------------|\n| `-f, --format {json,jsonl,csv,table,yaml}` | Output format |\n| `-t, --table` | Shorthand for `--format table` |\n| `-r, --raw, --raw-output` | Print scalar values without JSON quoting |\n| `-s, --stream` | Chunk-safe streaming for root-array JSON |\n| `--ndjson` | Force NDJSON mode |\n| `--follow` | Process NDJSON from stdin line-by-line |\n| `-n, --limit N` | Limit rows after query execution |\n| `-o, --out PATH` | Write output to a file |\n| `--jq` | Print the generated jq filter and exit |\n| `--explain` | Show parsed query details and generated jq |\n| `--time` | Print parse/execute/format timing to stderr |\n| `-p, --pretty` | Pretty-print JSON output |\n| `-w, --watch` | Rerun when the input file changes |\n| `--no-color` | Disable terminal color |\n| `--completions {bash,zsh,fish}` | Print shell completions |\n| `--version` | Print version |\n| `-i FILE, --interactive FILE` | Start the REPL |\n\n## Shell Completions\n\n```bash\n# Bash\neval \"$(jonq --completions bash)\"\n\n# Zsh\neval \"$(jonq --completions zsh)\"\n\n# Fish\njonq --completions fish \u003e ~/.config/fish/completions/jonq.fish\n```\n\n## Troubleshooting\n\n- **`jq` is not found**: Install jq and make sure it is on `PATH`.\n\n- **No query was provided**: Run `jonq data.json` to inspect the file, or pass a query such as `jonq data.json \"select *\"`.\n\n- **A field is missing or misspelled**: jonq validates top-level fields for normal file inputs and suggests close matches.\n\n- **Streaming mode rejected a query**: Use non-streaming mode for global operations like aggregation, grouping, sorting, distinct, or limit.\n\n- **The generated jq looks surprising**: Run the same command with `--explain` to see the parsed query and generated jq filter.\n\n## Known Limitations\n\n- jonq exposes a practical subset of jq, not the full jq language.\n- Streaming mode supports row-wise queries only.\n- Cross-file joins, window functions, and relational analytics are out of scope.\n- URL fetch is a convenience feature, not a full HTTP client.\n- Very large files can still be slow if the query requires full-input state.\n\n## Documentation\n\n- Full docs: https://jonq.readthedocs.io/en/latest/\n- Syntax reference: [SYNTAX.md](SYNTAX.md)\n- Usage examples: [USAGE.md](USAGE.md)\n- Contributing: [CONTRIBUTIONS.md](CONTRIBUTIONS.md)\n\n## License\n\njonq is licensed under the MIT License. See [License](License).\n\njonq depends on the [jq command-line JSON processor](https://stedolan.github.io/jq/). jq is licensed under the MIT License and is not bundled with jonq.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduriantaco%2Fjonq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fduriantaco%2Fjonq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduriantaco%2Fjonq/lists"}