SQLite JSON: Working with JSON in SQLite

One of SQLite’s strengths is its flexibility-it can handle relational data as well as semi-structured data like JSON. JSON (JavaScript Object Notation) has emerged as a popular data interchange format due to its simplicity, readability, and portability. Many applications today need to store and query JSON data.

It becomes easy to work with SQLite JSON data easy through its built-in JSON support. You can store JSON values in SQLite and use JSON functions to query, modify, and extract data from JSON documents stored in the database.

In this comprehensive guide, you will learn how to:

  • Store JSON documents in SQLite
  • Query and extract data from JSON columns using JSON functions
  • Modify JSON values in SQLite using various JSON functions
  • Index and optimize queries on JSON columns
  • Migrate JSON data between SQLite and other databases

We will explore all of these topics in detail with easy-to-follow examples. Let’s dive in!

How to Store JSON in SQLite

To store JSON in an SQLite database, you can use a TEXT or BLOB column type. JSON data is basically text, so the TEXT column is most commonly used.

Here is an example showing how to create a SQLite table with a JSON column and insert JSON data into it:

-- Create table
CREATE TABLE employees (
  id INTEGER PRIMARY KEY, 
  name TEXT,
  address JSON
);

-- Insert JSON data
INSERT INTO employees VALUES 
  (1, 'John Doe', '{
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021"
  }');

-- Verify inserted data  
SELECT * FROM employees;

This stores the employee’s address as a JSON object in the address column. The JSON data is treated as text and stored as-is in the column.

Some key points about storing JSON in SQLite:

  • JSON data must be valid JSON syntax. Invalid JSON values will result in an error.
  • JSON values can be inserted programmatically by generating JSON strings from code.
  • JSON text can include whitespace and indentation to make it human-readable. SQLite will store it as-is.
  • If needed, JSON can be minified before storing to reduce storage space.
  • BLOB can also be used instead of TEXT but offers no advantages for JSON storage.

This provides the basic capability to store JSON documents in your SQLite database. Next, let’s see how to query and manipulate this JSON data.

How to Query JSON Data in SQLite

SQLite provides a set of JSON functions that allow you to query values stored in JSON columns. These functions give you the ability to extract specific values from JSON documents using a JSON path.

The key functions for querying JSON data are:

  • json_extract – Extract a scalar value from JSON using path
  • json_type – Get type of value extracted from JSON
  • json_valid – Validate if a string contains valid JSON

Let’s see examples of using these functions:

-- Get city for employee id 1
SELECT json_extract(address, '$.city') 
FROM employees
WHERE id = 1;

-- Get type of postalCode value 
SELECT json_type(address, '$.postalCode')  
FROM employees
WHERE id = 1; 

-- Validate JSON 
SELECT json_valid('{ "name": "John" }');

The json_extract function lets you pull out specific values from a JSON document by specifying the path. Note the $ prefix before the path.

Some things to know about JSON paths:

  • Path starts with $ to indicate root element
  • Use . to specify nested fields like $.address.city
  • Use [n] for array access like $.phoneNumbers[0]
  • * can be used as wildcard for anything

The json_type function returns the JSON type of the extracted value – integerrealtextblob, etc.

And json_valid lets you verify if a string contains valid JSON or not.

In addition to these, there are several other JSON functions like json_arrayjson_objectjson_insertjson_replace that can create or modify JSON values. We will see examples of using these later.

How to Access JSON Fields in SQLite Query

You can directly access JSON fields in other parts of the query like the WHERE clauseJOIN condition, ORDER BY, etc.

SQLite allows you to specify a path with the ->> operator to extract a JSON value. For example:

-- Get employees in New York 
SELECT *
FROM employees
WHERE address->>'$.city' = 'New York';

-- Order by zip code
SELECT * 
FROM employees
ORDER BY address->>'$.postalCode'; 

This shorthand is equivalent to using json_extract but provides cleaner syntax in queries.

How to Modify JSON values in SQLite

In addition to querying JSON columns, SQLite also provides functions to modify, insert, update, or delete data from JSON documents.

Some common JSON modification functions are:

  • json_set – Set value of a JSON element
  • json_insert – Insert into a JSON array or object
  • json_replace – Replace value of a JSON element
  • json_remove – Remove element from JSON

Let’s see how to use these functions to manipulate JSON values:

-- Change city to Chicago
UPDATE employees 
SET address = json_set(address, '$.city', 'Chicago')
WHERE id = 1;

-- Add a phone number 
UPDATE employees
SET address = json_insert(address, '$.phoneNumbers[0]', '123-456-7890') 
WHERE id = 1;

-- Change postal code
UPDATE employees
SET address = json_replace(address, '$.postalCode', '60611')
WHERE id = 1;

-- Remove state 
UPDATE employees
SET address = json_remove(address, '$.state')
WHERE id = 1;

You can see how these functions allow modifying JSON documents by inserting, replacing, or removing elements as needed.

Some key points:

  • json_set will add new element if path doesn’t exist
  • json_insert only inserts if path exists
  • json_replace replaces value if path exists else no change
  • Removed elements using json_remove cannot be restored

These functions enable updating your JSON documents just like you would update rows or columns in a relational table.

How to Index JSON Columns in SQLite

To optimize performance, you may want to create indexes on your JSON columns – especially if they are used frequently for filtering or sorting.

SQLite allows you to index expressions, so you can create indexes on specific JSON fields like:

-- Index for postal code
CREATE INDEX idx_postal_code ON employees((address->>'$.postalCode'));

-- Multi-column index
CREATE INDEX idx_address ON employees(address->>'$.city', address->>'$.state'); 

This can speed up queries like:

-- Make use of index 
SELECT *
FROM employees
WHERE address->>'$.postalCode' = '60611';

You should create indexes to match your typical query patterns and filters. Here are some tips:

  • Prefer indexes on smaller TEXT/INTEGER over larger BLOB/strings
  • Use multi-column indexes for queries filtering on multiple fields
  • Limit indexes to only required columns – avoid indexing entire JSON
  • Test queries with/without indexes to validate performance gains

Also, rebuilding indexes after large data modifications in JSON can restore optimal performance.

How to Handle Nested JSON Data in SQLite

In real-world scenarios, JSON documents can have complex nested structures with multiple levels of arrays and objects. SQLite’s JSON functions work consistently across nested data.

Consider a JSON document like:

{
  "name": "John",
  "age": 35, 
  "address": {
    "line1": "123 Main St",
    "city": "Chicago",
    "state": "IL",
    "zip": 60611   
  },
  "phoneNumbers": [
    "123-456-7890",
    "098-765-4321"  
  ]
}

To access nested fields and arrays, you simply extend the JSON path:

-- Access nested fields
SELECT json_extract(data, '$.address.city') FROM users WHERE ...

-- Get array element  
SELECT json_extract(data, '$.phoneNumbers[0]') FROM users WHERE ... 

-- Nested array access
SELECT json_extract(data, '$.address.line2[0]') FROM users WHERE ...

JSON functions seamlessly handle arbitrarily complex nested data structures.

One exception is the json_array() function which accepts scalar values as arguments. To insert nested JSON arrays/objects into another JSON document, you need to:

  1. Construct nested JSON separately
  2. Insert it using json_insert() or json_set()

For example:

-- Construct nested JSON
SELECT json_array(json_object('line1', '123 Main St')); 

-- Insert into document  
UPDATE users 
SET data = json_insert(data, '$.address.line2', 
  json_array(json_object('line1', '123 Main St')))
WHERE ...

So you need to build up nested structures before inserting into the main document.

How to Migrate JSON Data from SQLite

A common requirement is migrating JSON data from SQLite to another database or file format like MongoDB, DynamoDB, CSV, etc.

This is straightforward – you extract the JSON data and export it to the desired target system. Here is an example showing how to extract JSON data from SQLite and convert to CSV:

-- Query JSON data
SELECT json_extract(data, '$.name') AS name,  
       json_extract(data, '$.age') AS age,
       json_extract(data, '$.address.line1') AS line1,
       json_extract(data, '$.address.city') AS city       
FROM users;

-- Export output to CSV 
.mode csv
.headers on 
.output data.csv

This exports extracted fields to a CSV file that can be loaded elsewhere.

You can use similar techniques to export JSON documents to any external datastore:

  • Extract required fields or full JSON
  • Optionally transform to another format
  • Load into target datastore

SQLite’s JSON functions provide the flexibility to easily migrate your JSON data.

Summary of Best Practices of JSON in SQLite

To summarize, here are some recommended best practices for working with JSON in SQLite:

  • Use TEXT columns to store JSON by default rather than BLOB
  • Validate syntax before insertion to prevent errors
  • Normalize over nesting where possible for simpler querying
  • Use JSON functions like json_extract for querying instead of string functions
  • Index common fields used for filters and sorting
  • Construct nested JSON before insertion into documents
  • Extract data rather than entire columns when migrating
  • Test integrations with sample data before production migrations

By following these best practices, you can build robust applications on SQLite that leverage its JSON capabilities.

Conclusion

This guide covered the key aspects of working with JSON data in SQLite:

  • Storing JSON documents in TEXT columns
  • Querying and extracting values using json_extract and other JSON functions
  • Modifying JSON values with json_set, json_insert, json_replace etc
  • Creating indexes on JSON fields for performance
  • Dealing with nested JSON structures
  • Migrating JSON data from SQLite

As you can see, SQLite provides extensive support through its built-in JSON handling functions. You can store, query, and manipulate JSON just like you would with regular relational data.