Bryan Jones : Build Engineer
Matt Thomas : Principal System Engineer - UI
Data Category | Description |
---|---|
Key Value | Simple KV |
Columnar | Good for Analytical Processing |
Graph | Relationships b/w Entities |
Document | Embedding Joins |
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It is easy for humans to read and write. It is easy for machines to parse and generate.
There are many circumstances where you wish to store document style data, such as UI preferences, incoming data that is not processed locally on the backend.
Why stand up document store increasing complexity of your existing infrastructure when most modern relational databases have the ability to store JSON data.
RDBMS + NORMALIZATION - Minimize Duplicate Data and Data Anomalies
JSON + DENORMALIZATION - Minimize the Need for Joins
(And Support Flexible Schemas)
Semi-Tangible Examples
Single Page Applications often have a data stores that need to be persisted but not necessary understood by the backend API service as they are only used by the front-end.
Consuming 3rd party API response may not require consumption of the data immediately.
The response(s) can be stored, later extracting section(s) of the response to be consumed.
"...all men JSON implementations are created equal..."
Version | Feature(s) |
---|---|
9.2 | JSON Validation |
9.3 | Extract Operators |
9.4 | JSONB |
9.5 |
JSONB Modifiers |
9.6 | jsonb_insert() |
10 | Full Text Search for JSON/B |
JSON | JSONB (Binary) |
---|---|
Preserves whitespace | Removes whitespace b/w keys |
Preserves key order | Arbitrary key order |
Duplicate keys | No duplicates |
Heavy writes (No indexes) | Heavy reads (Indexes allowed) |
E.g. Log files; API responses | Recommended for general use |
JSON (Binary) |
---|
Removes whitespace b/w keys |
Arbitrary key order |
No duplicates |
Indexes allowed via virtual columns |
1 Gb per field |
LONGTEXT aka JSON |
---|
Preserves whitespace |
Preserves key order |
Duplicate keys |
Indexes allowed via virtual columns |
4 Gb per field |
CHECK Constraint required to validate document on column definition |
TEXT |
---|
Preserves whitespace |
Preserves key order |
Duplicate keys |
No enforced field limit |
json() function call required to validate document on statement |
PostgreSQL
ALTER TABLE users ADD contacts JSONB;
MySQL
ALTER TABLE users ADD contacts JSON;
MariaDB
ALTER TABLE users ADD contacts JSON CHECK(JSON_VALID(user));
SQLite
ALTER TABLE users ADD contacts TEXT;
PostgreSQL/MySQL/MariaDB
INSERT INTO users (user_name, contacts) VALUES ('kenny', '{ "email": "kenny@aol.com", "twitter": "@drken"}');
INSERT INTO users (user_name, contacts) VALUES ('sam', '{ "email": "sam@yahoo.com", "twitter": "@sam88", "facebook": "sam88"}');
SQLite
INSERT INTO users (user_name, contacts) VALUES ('kenny', json('{ "email": "kenny@aol.com", "twitter": "@drken"}'));
PostgreSQL
UPDATE users SET contacts = JSONB_INSERT(contacts, '{phone}', '"314-222-2222"') WHERE user_name = 'kenny';
(Including returning a subsection of the document)
PostgreSQL
SELECT user_name, contacts -> 'twitter' AS twitter FROM users WHERE user_name = 'kenny';
SELECT user_name, contacts ->> 'twitter' AS twitter FROM users WHERE user_name = 'kenny';
SELECT user_name, contacts ->> 'twitter' AS twitter FROM users WHERE contacts ->> 'twitter' IS NOT NULL;
MySQL
SELECT user_name, contacts->'$.twitter' AS twitter FROM users WHERE user_name = 'kenny';
SELECT user_name, contacts->>'$.twitter' AS twitter FROM users WHERE user_name = 'kenny';
SELECT user_name, contacts->>'$.twitter' AS twitter FROM users WHERE contacts->>'$.twitter' IS NOT NULL;
MariaDB/SQLite
SELECT user_name, JSON_VALUE(contacts, '$.twitter') AS twitter FROM users WHERE user_name = 'kenny';
(Including updating a subsection of the document)
PostgreSQL
UPDATE users SET contacts = JSONB_SET(contacts, '{twitter}', '"@fred"') WHERE user_name = 'kenny';
MySQL/MariaDB/SQLite
UPDATE users SET contacts = JSON_SET(contacts, '$.twitter', '@fred') WHERE user_name = 'kenny';
(Including deleting a subsection of the document)
PostgreSQL
UPDATE users SET contacts = contacts - 'twitter' WHERE user_name = 'kenny';
MySQL/MariaDB/SQLite
UPDATE users SET contacts = JSON_REMOVE(contacts, '$.twitter') WHERE user_name = 'kenny';
PostgreSQL
CREATE INDEX idx_users_contacts ON users USING GIN (contacts);
CREATE INDEX idx_users_contacts_email ON users USING GIN ((contacts -> 'email'));
MySQL
/* Create the virtual column: */
ALTER TABLE users ADD contacts_email VARCHAR(255) AS (contacts->>'$.email');
ALTER TABLE users ADD contacts_email VARCHAR(255) AS (contacts->>'$.email') STORED;
/* Create your traditional index: */
ALTER TABLE users ADD INDEX (contacts_email);
ALTER TABLE users ADD INDEX (contacts_email_stored);
MariaDB
/* Create the virtual column: */
ALTER TABLE users ADD COLUMN contacts_email VARCHAR(255) AS (JSON_VALUE(contacts, '$.email')) VIRTUAL;
/* Create your traditional index: */
ALTER TABLE users ADD INDEX (contacts_email);
ALTER TABLE users ADD INDEX (contacts_email_stored);