liteJQ is an SQLite extension, written in C, that brings jq support to SQLite.
It uses vanilla libjq.
Note: If you like the idea, but you're more into Postgres, check out: pgJQ: jq extension for Postgres
SQLite has been supporting JSON for years. Complex queries, however, involving JSON can be more cumbersome to write and understand, especially when compared to more complex systems like PostgreSQL. liteJQ attempts to alleviate that by bringing the expressive power of jq into SQLite.
makeThis produces a litejq binary object, which should be loaded in SQLite at runtime.
Verify the installation.
sqlite3 :memory: <<EOF
.load ./litejq
select jq('{"key": "litejq is loaded"}', '.key')
EOFSELECT jq(json, jqprog)
We'll use the movie dataset as a running example.
sqlite3 movies.db < ./data/movies.sqlWe have a very simple schema:
CREATE TABLE [movies] (
"d" TEXT -- json
);
Column d holds json values in plain text like this.
{
"title": "The Corn Is Green",
"year": 1945,
"cast": [
"Bette Davis",
"Joan Lorring",
"John Dall"
],
"genres": [
"Drama"
],
"href": "The_Corn_Is_Green_(1945_film)",
"extract": "The Corn Is Green is a 1945 American drama film starring Bette Davis as a schoolteacher determined to bring education to a Welsh coal mining town despite great opposition. It was adapted from the 1938 play of the same name by Emlyn Williams, which originally starred Ethel Barrymore.",
"thumbnail": "https://upload.wikimedia.org/wikipedia/en/thumb/b/bf/The-corn-is-green-poster.jpg/320px-The-corn-is-green-poster.jpg",
"thumbnail_width": 320,
"thumbnail_height": 248
}In any session, you should load the extension first after building it, like this:
.load ./litejq
Then you can start doing jq magic.
Let's see some example queries.
List all movie titles
select jq(d, '.title')
from movies;To find movies released after a specific year, for example, 1980
select jq(d, '{title: .title, year: .year}')
from movies
where jq(d, '.year > 1980');The above query is equivalent to this one
select jq(d, '{title: .title, year: .year}')
from movies
where jq(d, '.year') > 1980;Extract Movies with Specific Keywords in Extract
select jq(d, '.extract')
from movies
where jq(d, '.extract | contains("silent")');Filter movies by a specific genre (e.g., Drama)
select jq(d, '{title: .title, year: .year, genres: .genres}')
from movies
where jq(d, '.genres[] == "Drama"');Filter movies where "Joan Lorring" and "John Dall" played together
select jq(d, '{title: .title, year: .year, cast: .cast}')
from movies
where jq(d, '.cast | contains(["Joan Lorring", "John Dall"])');Group by movies by release year
select jq(d, '.year'), count(*)
from movies
group by jq(d, '.year')For this to work, you'll need development files for both SQLite and jq.
brew install jq sqlite3
make allI've found that brew installs header files auomatically for you,
so there's nothing else you have to do
Verify installation
sqlite3 :memory: <<EOF
.load ./litejq
select jq('{"key": "value"}', '.key')
EOFsudo apt install sqlite3 libsqlite3-dev jq libjq-devOn Linux, sometimes things can be trickier because
many distros don't have jq configured with pkg-config
so your best guess would be installing jq from source first.
If you already have jq installed to a known prefix,
try using it explicitly:
JQ_PREFIX=/usr/local makeIf this doesn't work, you can (and probably should) build it from source.
cd /tmp &&
wget "https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-1.7.1.tar.gz" &&
tar xzf jq-1.7.1.tar.gz &&
cd jq-1.7.1 &&
./configure --with-oniguruma=builtin --prefix=/usr/local &&
sudo make installThen try again
makesqlite3 :memory: <<EOF
.load ./litejq
select jq('{"key": "litejq is loaded"}', '.key')
EOF