Professional Documents
Culture Documents
CONTENTS
Hybrid Relational/
∙ Hybrid Relational/JSON Overview
∙ Reading Fields
∙ Searching Fields
∙ Reading Arrays
∙ Indexing Fields
∙ Integrity Constraints
SHANE JOHNSON
∙ Additional Resources
SR. DIRECTOR OF PRODUCT MARKETING AT MARIADB
JSON has become the de facto standard for sending and receiving have authors, movies have resolutions. Thus, these properties are
data — in particular, between application servers and the browsers/ stored in a separate JSON column. A JSON column also allows easy
mobile applications connected to them. addition of new properties in the future and properties with multiple
and/or complex values.
In the late 2000s, document databases such as MongoDB were built
to store and query JSON documents. Today, relational databases For example, a movie may have multiple cuts, with each cut having
can store and query data as relations (i.e., rows and columns) or its own title and running time. Because cuts are unique to a movie, it
JSON — and with standard SQL. may not make sense to store them in a separate table with a one-to-
many relationship.
There are a few ways to take advantage of the JSON support within
relational databases: DATA QUERYING
JSON documents are queried with SQL functions. The core functions
• Storing data as relations, querying it as JSON documents.
(e.g., reading a field within a JSON document) are defined in the
• Storing data as JSON documents, querying it as relations.
SQL:2016 standard.
• Storing data as relations with JSON documents, querying it
With these functions, queries can access both relations and JSON
as relations and/or JSON documents.
documents at the same time.
The third approach, hybrid relational/JSON data modeling and
querying, is covered in this DZone Refcard.
HYBRID RELATIONAL/JSON
OVERVIEW
Extending relations with JSON documents allows easier, faster
application development while at the same time maintaining the
operational benefits of relational databases — transactions, data
integrity, and relationships.
DATA MODELING
Attributes common to all objects should be stored as relations. The
examples in this DZone Refcard use a simple product catalog table for
both movies and books. Every product has a name and price, so the
product table has name and price columns. However, whereas books
1
THE SKY IS
TRULY
THE LIMIT
SKYSQL. The ultimate MariaDB Cloud is here.
JSON functions often take one or more the following arguments: FOUNDATION "PROPS" (JSON DOCUMENT)
READING FIELDS
MARIADB SERVER
The JSON_VALUE function returns the value of string, number and
The examples below use the SQL JSON functions available in
boolean fields (i.e., scalar fields).
MariaDB Server 10.4. MariaDB Server implements all JSON functions
defined in the SQL:2016 standard and includes additional ones that Note: If the JSON document does not contain the field specified by the
may or may not be implemented in other relational databases. JSONPath expression, a NULL value will be returned.
INSERT INTO products (name, type, price, props) Alien Blu-ray 14.99 Blu-ray
VALUES ('Alien', 'Movie', 14.99, '{"video": {"format":
"Blu-ray", "resolution": "1080p", "aspectRatio":
CREATING AND UPDATING FIELDS
"1.85:1"}, "cuts": [{"name": "Theatrical", "runtime":
138}, {"name": "Special Edition", "runtime": 155}], The JSON_INSERT, JSON_REPLACE , JSON_SET, and JSON_REMOVE
"audio": ["DTS HD", "Dolby Surround"]}'); functions modify JSON documents.
INSERT INTO products (name, type, price, props) Note: JSON_SET can insert a field or update an existing one.
VALUES ('Foundation', 'Book', 7.99, '{"author": "Isaac
Asimov", "page_count": 296}'); JSON_INSERT|REPLACE|SET
UPDATE products
SELECT * FROM products;
SET props = JSON_INSERT(props, '$.disks', 1)
WHERE id = 1;
ID NAME TYPE PRICE PROPS
The JSON_CONTAINS function returns 1 if the JSON document APPEND and JSON_ARRAY_INSERT functions add an element to an
contains a field with the value provided, optionally at a provided array, the former at the end and the latter at a specific position.
EXPLAIN
JSON_QUERY
SELECT name, type, price
FROM products
SELECT name, JSON_QUERY(props, '$.video') AS video
WHERE video_resolution = '1080p';
FROM products
WHERE id = 1;
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS
NAME AUDIO 1 simple products all null
{"format": "Blu-ray", "resolution": "1080p",
Alien
"aspectRatio": "1.85:1", "3d": true} CREATE INDEX resolutions ON products(video_resolution);
EXPLAIN
CREATING OBJECTS
SELECT name, type, price
JSON_OBJECT FROM products
WHERE video_resolution = '1080p';
The JSON_OBJECT function creates a JSON document from key/
value pairs. The key is arbitrary. The value can be the name of a non-
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS
JSON column or the scalar result of a JSON function.
1 simple products ref resolutions
SELECT id, JSON_OBJECT('name', name,
'type', type, 'price', price) AS json
FROM products INTEGRITY CONSTRAINTS
WHERE id = 1; JSON functions can be used in check constraints in order to enforce
the integrity of JSON documents — for example, to ensure required
ID JSON fields, field types, and field sizes.
1 {"name": "Alien", "type": "Movie", "price": 14.99}
ALTER TABLE products
ADD CONSTRAINT check_attr
JSON_MERGE_PATCH CHECK (type != ‘M’ or (type = ‘M’ and
JSON_TYPE(JSON_QUERY(attr, ‘$.video’)) = ‘OBJECT’
The JSON_MERGE_PATCH function merges two JSON documents,
and
and can be used with JSON_OBJECT to create a JSON document by JSON_TYPE(JSON_QUERY(attr, ‘$.cuts’)) = ‘ARRAY’ and
merging one or more non-JSON columns with a JSON column. JSON_TYPE(JSON_QUERY(attr, ‘$.audio’)) = ‘ARRAY’
and
SELECT JSON_MERGE( JSON_TYPE(JSON_VALUE(attr, ‘$.disks’)) = ‘INTEGER’
JSON_OBJECT('id', id, 'name', name), props) AS and
data JSON_EXISTS(attr, ‘$.video.resolution’) = 1 and
FROM products JSON_EXISTS(attr, ‘$.video.aspectRatio’) = 1 and
WHERE id = 1; JSON_LENGTH(JSON_QUERY(attr, ‘$.cuts’)) > 0 and
JSON_LENGTH(JSON_QUERY(attr, ‘$.audio’)) > 0));
JSON
INSERT INTO products (type, name, format, price, attr)
{"id": 1, "name": "Alien", "video": {"format": "Blu-
VALUES (‘M’, ‘Tron’, ‘Blu-ray’, 29.99, ‘{“video”:
ray", "resolution": "1080p", "aspectRatio": "1.85:1",
{“aspectRatio”: “2.21:1”}, “cuts”: [{“name”:
"3d": true}, "cuts": [{"name": "Theatrical", "runtime":
“Theatrical”, “runtime”:96}], “audio”: [“DTS HD”,
138}, {"name": "Special Edition", "runtime": 155}],
“Dolby Digital”], “disks”: 1}’);
"audio": ["DTS HD", "Dolby Surround"], "disks": 1,
"languages": ["English", "Spanish", "German", "French"]}
Note: The statement above is inserting a movie without a
resolution field.
INDEXING FIELDS
ERROR 4025 (23000): CONSTRAINT ‘check_attr’ failed for
Indexes can be created on fields within JSON documents by creating
‘test’.’products’
virtual columns (i.e., non-persistent, computed columns) using a
JSON function and indexing them.
JSON_ARRAYAGG Y
JSON_KEYS Get all of the keys within a JSON document or a nested JSON object N
JSON_LENGTH Get the length of a JSON document or the value of a specific field N
JSON_OBJECTAGG Y
JSON_QUERY Get the value of a specific JSON object or array within a JSON document Y
JSON_SEARCH Get the first or all paths to fields containing a specific value N
JSON_SET Insert or update the value of a specific field within a JSON document N
JSON_VALUE Get value of a specific JSON string, number of boolean within a JSON document Y
*The JSON_TABLE function is planned for MariaDB Server 10.5 (beta as of March 2020).
For new applications, or applications being refactored, now is Shane Johnson is the Senior Director of Product
the perfect time to adopt a hybrid relational/JSON data model. Marketing at MariaDB. Prior to MariaDB, he led
product and technical marketing at Couchbase.
Identifying places where the use of JSON documents — both in the In a past life, he performed technical roles in development,
data model and in query results — can streamline development architecture, and evangelism at Red Hat and other companies.
His background is in Java and distributed systems.
and provide greater flexibility in the future.