README.org

June 30, 2025 ยท View on GitHub

  • What is it? =jq-mode= is an emacs major mode for editing [[https://github.com/stedolan/jq][jq]]-scripts.

  • Getting started [[https://melpa.org/#/jq-mode][file:https://melpa.org/packages/jq-mode-badge.svg]] [[https://stable.melpa.org/#/jq-mode][file:https://stable.melpa.org/packages/jq-mode-badge.svg]]

    • Download jq-mode.el and put it in a directory somewhere.
    • Add the following to your .emacs file

    #+BEGIN_SRC emacs-lisp (add-to-list 'load-path "/path/to/jq-mode-dir") (autoload 'jq-mode "jq-mode.el" "Major mode for editing jq files" t) (add-to-list 'auto-mode-alist '("\.jq$" . jq-mode)) #+END_SRC

    Now jq-mode will load whenever you visit a file whose name ends with .jq. Alternatively, run =M-x jq-mode= in an existing buffer containing jq commands.

  • Interactive mode =jq-mode= can also be used interactively in a JSON buffer. If you add the following to your .emacs file

    #+BEGIN_SRC emacs-lisp (with-eval-after-load "json-mode" (define-key json-mode-map (kbd "C-c C-j") #'jq-interactively)) #+END_SRC

    or you can call =M-x jq-interactively=. =jq-interactively= runs the expression that is written in the minibuffer iteratively over the JSON buffer. Press =C-g= to abort, =C-j= for newline, =RET= commits any changes.

** Use yq for yaml

It is possible to use [[https://github.com/kislyuk/yq][yq]] to process yaml with the interactive mode instead:

#+BEGIN_SRC emacs-lisp (setq jq-interactive-command "yq" jq-interactive-font-lock-mode #'yaml-mode jq-interactive-default-options "--yaml-roundtrip") #+END_SRC

  • Org babel

    =jq-mode= provides =ob-jq= for working with literate programming in Org mode.

    Add =jq= under =org-babel-load-languages= in your .emacs file

    #+BEGIN_SRC emacs-lisp (org-babel-do-load-languages 'org-babel-load-languages '((jq . t))) #+END_SRC

** Why should I write jq expressions in org documents?

Writing =jq= expressions in org documents is a huge usability improvment over writing them on the command line.

** jq specific header arguments

=ob-jq= provides some additional header arguments:

  • =:compact= :: Add =-c= to =jq= arguments list suppressing pretty printing

** Examples

*** Using ob-jq with a file as input

  • =:in-file= is used to set the input filename. In this example [[https://pastebin.com/UKtNrGGt][apartments.json]] is used.
  • =:cmd-line= can be used to pass =jq= extra command line parameters.
  • =:wrap= can be used to wrap the result in another org block. In this example, it's a src block that contains JSON.

#+begin_src org ,#+begin_src jq :in-file apartments.json :cmd-line "-r" :wrap src json [ .[] | select(.addr_prefecture == "Aichi") ] | sort_by(.monthly_cost) | .[] | { link, monthly_cost } ,#+end_src

,#+RESULTS: ,#+begin_src json { "link": "https://realestate.co.jp/en/rent/view/1095206", "monthly_cost": 157200 } { "link": "https://realestate.co.jp/en/rent/view/1095222", "monthly_cost": 163200 } ,#+end_src #+end_src

*** Using ob-jq with JSON data from an inert block

  • If you want to include the JSON in the org document, give it a =#+name:=.
  • Then use =:stdin= to feed it into a jq src block like this.

#+begin_src org ,#+name: inert ,#+begin_example { "name": "gg" } ,#+end_example

,#+begin_src jq :stdin inert .name ,#+end_src

,#+RESULTS: : "gg" #+end_src

*** Using ob-jq with the output of another block

  • It works just like passing in an inert block. Just give it a =#+name:= and pass it in via =:stdin=.

#+begin_src org ,#+name: btcusd ,#+begin_src sh :results output :wrap src json curl --silent 'https://www.bitstamp.net/api/v2/ohlc/btcusd/?start=1359936000&limit=3&step=60' ,#+end_src

,#+RESULTS: btcusd ,#+begin_src json {"data": {"pair": "BTC/USD", "ohlc": [{"timestamp": "1359936000", "open": "20.29", "high": "20.29", "low": "20.29", "close": "20.29", "volume": "0.00000000"}, {"timestamp": "1359936060", "open": "20.29", "high": "20.29", "low": "20.29", "close": "20.29", "volume": "0.00000000"}, {"timestamp": "1359936120", "open": "20.29", "high": "20.29", "low": "20.29", "close": "20.29", "volume": "0.00000000"}]}} ,#+end_src

,#+begin_src jq :stdin btcusd :wrap src json .data.ohlc | .[] | { close, timestamp: .timestamp | tonumber | strftime("%Y-%m-%dT%H:%M:%S") } ,#+end_src

,#+RESULTS: ,#+begin_src json { "close": "20.29", "timestamp": "2013-02-04T00:00:00" } { "close": "20.29", "timestamp": "2013-02-04T00:01:00" } { "close": "20.29", "timestamp": "2013-02-04T00:02:00" } ,#+end_src #+end_src