A jq clone focused on correctness, speed, and simplicity
jaq (pronounced like Jacques1) is a clone of the JSON data processing tool jq. jaq aims to support a large subset of jq’s syntax and operations. jaq focuses on three goals:
jaq aims to provide a more correct and predictable implementation of jq, while preserving compatibility with jq in most cases.
The creator of jaq was bothered by jq’s long start-up time, which amounts to about 50ms on their machine. This can be particularly noticeable when processing a large number of small files. jaq starts up about 30 times faster than jq 1.6 and outperforms jq on many other benchmarks.
jaq aims to have a simple and small implementation in order to reduce the potential for bugs and facilitate contributions. The creator drew inspiration from another Rust program, namely jql, but jaq aims to closely imitate jq’s syntax and semantics to allow users proficient in jq to easily use jaq.
To compile jaq, you need a Rust toolchain. You can find instructions on how to install Rust at https://rustup.rs/. Please note that Rust compilers shipped with Linux distributions may be too outdated to compile jaq.
Once you have the Rust toolchain installed, you can install jaq using one of the following commands:
cargo install jaq
git clone https://github.com/jmespath/jaq.git
cargo build --release
After the installation, you can run jaq by executing the following command:
jaq [options] [jq_filter] [file ...]
jaq should work on any system supported by Rust. If it does not, please file an issue on the GitHub repository.
Here are some examples of what jaq can currently do:
jaq '.name' example.json
This command accesses the “name” field in the “example.json” file.
jaq '.numbers | . + 1' example.json
This command adds 1 to each element in the “numbers” array in the “example.json” file.
jaq '[$obj1, $obj2] | . == .' example.json
This command constructs an array with two objects, and checks if the first object is equal to the second object in the “example.json” file.
jaq '. | select(.age > 30)' example.json
This command selects all elements in the array that have an “age” greater than 30 in the “example.json” file.
jaq 'map(.value) | add / length' example.json
This command reads all input values into an array, gets the average of its elements by summing them and dividing by the length of the array in the “example.json” file.
These examples give you an impression of what jaq can currently do. You should obtain the same outputs by replacing jaq with jq. If not, please file an issue on the GitHub repository.
The creator of jaq has conducted several benchmarks to compare the performance of jaq, jq, and gojq. The benchmarks include empty, bf-fib, and various filters with different inputs.
Based on the benchmark results, jaq-1.2 is fastest on 16 benchmarks, jq-1.7 is fastest on 2 benchmarks, and gojq-0.12.13 is fastest on 1 benchmark. gojq performs better on the tree-flatten benchmark due to its native implementation of the flatten filter.
Overall, jaq has shown impressive performance compared to jq and gojq in many cases.
Contributions to extend jaq are highly welcome. The creator of jaq has defined several filters via more basic filters, and their definitions can be found in std.jq. jaq imports many filters from libm and follows their type signature.
jaq currently does not aim to support several features of jq, such as 64-bit floating-point numbers (floats) for any number. jaq interprets numbers such as 0 or -42 as machine-sized integers and numbers such as 0.0 or 3e8 as 64-bit floats. This is to avoid rounding errors that may lead to wrong results.
jaq also has some differences in its implementation compared to jq, such as the interpretation of assignments and the behavior of division by 0. These differences are explained in detail in the documentation.
Jaq – A jq clone focused on correctness, speed, and simplicity