visit
I’m willing to bet that if you’re reading this article you’ve at least heard of . Heck, maybe you’ve even used it at some point. But, if not, I highly recommend that you give it a quick glance as, at the highest level, it’s a pretty solid, free (yea, free) open-source database solution that you can use for anything from some lightweight tinkering to supporting fully-fledged, production-grade applications.
Much, much more.
Keying off of the success that NoSQL solutions have been able to achieve by using semi-structured data in that time, over the past few years JSON integrations have made their way into the relational world. And for good reason. The ability to store JSON documents within a relational database allows you to create hybrid data models, containing both structured and semi-structured data, and enjoy all of the benefits of JSON without having to sacrifice the advantages of relational databases (e.g. SQL and all things data integrity).
Keying off of the success that NoSQL solutions have been able to achieve by using semi-structured data in that time, over the past few years JSON integrations have made their way into the relational world*.*
To help walk-through the JSON capabilities that are available within MariaDB I’m going to be using a hypothetical application. This application will only contain one table, called locations, that will store, yep, you guessed it, locations. Simple enough, right?
From the simplest standpoint, geographic locations, no matter the type, contain foundational information such as the name, type, longitude and latitude. But, depending on the type, each location could have different details.
CREATE TABLE locations (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
type CHAR(1) NOT NULL,
latitude DECIMAL(9,6) NOT NULL,
longitude DECIMAL(9,6) NOT NULL,
attr JSON,
PRIMARY KEY (id)
);
Note that the attr column included within the locations table is defined with a JSON data type. More specifically the column is using a JSON alias data type. That means there’s no actual JSON data type, but, instead, the JSON specified data type is converted into an existing data type within MariaDB.
…there’s no actual JSON data type, but, instead, the JSON specified data type is converted into an existing data type within MariaDB.
Taking a closer look, we can use the SHOW CREATE
query to inspect the details of what’s actually been created.
SHOW CREATE TABLE locations;
CREATE TABLE locations (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
type CHAR(1) NOT NULL,
latitude DECIMAL(9,6) NOT NULL,
longitude DECIMAL(9,6) NOT NULL,
attr LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL
CHECK (JSON_VALID(`attr`)
PRIMARY KEY (id)
);
Notice that the data type for the attr column is LONGTEXT
. Beyond that you’ll see that there are a few constraints added to the field for the character set and collation. Most importantly, however, is the CHECK
constraint, which indicates a function that will be executed when the data in attr has been modified, either through insertion or updating.
The JSON data that you insert is contained within quotes, just like any other string-based information you’d insert. The only difference is that the string must be valid JSON.
INSERT INTO locations (type, name, latitude, longitude, attr) VALUES
('R', 'Lou Malnatis', 42.0021628, -87.7255662,
'{"details": {"foodType": "Pizza", "menu": "//www.loumalnatis.com/our-menu"},
"favorites": [{"description": "Pepperoni deep dish", "price": 18.75},
{"description": "The Lou", "price": 24.75}]}');
INSERT INTO locations (type, name, latitude, longitude, attr) VALUES
('A', 'Cloud Gate', 41.8826572, -87.6233039,
'{"category": "Landmark", "lastVisitDate": "11/10/2019"}');
…you can specify different JSON data, with completely different structures, within the insert to the same table.
You’ve probably picked up on it by now but managing JSON data within MariaDB really boils down to using predefined functions. For the rest of this article we’ll be taking a look at several of the functions that are available to you.
The function returns a JSON scalar value from the specified path in the specified data. In the following example I’ve used the attr column as the “specified data”, but note that the JSON supplied to the function could just as well be a raw string of JSON data.
SELECT name, latitude, longitude,
JSON_VALUE(attr, '$.details.foodType') AS food_type
FROM locations
WHERE type = 'R';
And if you’re wondering “what about handling null/non-existent values?”, because, due to the nature and, really, the purpose of semi-structured, that’s kind of the point. Yep, the JSON_VALUE()
function handles that.
What about handling null/non-existent values? …Yep
You’re also not limited to using the JSON functions strictly as part of the SELECT
clause. You can just as easily use them within the filtering portions.
SELECT id, name, latitude, longitude
FROM locations
WHERE type = 'S' AND
JSON_VALUE(attr, '$.details.yearOpened') = 1924;
The function accepts JSON data and a JSON path and returns JSON data. The difference between JSON_VALUE()
and JSON_QUERY()
is that JSON_QUERY()
returns entire JSON object data.
SELECT name, description,
JSON_QUERY(attr, '$.details') AS details
FROM locations
WHERE type = 'R'
The JSON_QUERY()
function can also return arrays.
SELECT name, description,
JSON_QUERY(attr, '$.teams') AS home_teams
FROM locations
WHERE type = 'S';
ALTER TABLE locations ADD COLUMN
food_type VARCHAR(25) AS (JSON_VALUE(attr, '$.details.foodType')) VIRTUAL;
CREATE INDEX foodtypes ON locations(food_type);
As you know, reading data is really only half the battle. To really get the value out of being able to store JSON data within a relational database you also need to be able to modify, or write, it. Luckily, MariaDB provides a bunch of functionality for this as well.
UPDATE locations
SET attr = JSON_INSERT(attr,'$.nickname','The Bean')
WHERE id = 8;
You can also create new arrays using the function. Then, within the JSON_INSERT()
function, the new array can be inserted into the specified JSON data (in this case the attr field).
UPDATE locations
SET attr = JSON_INSERT(attr,
'$.foodTypes',
JSON_ARRAY('Asian', 'Mexican'))
WHERE id = 1;
UPDATE locations
SET attr = JSON_ARRAY_APPEND(attr,
'$.foodTypes', 'German’)
WHERE id = 1;
UPDATE locations
SET attr = JSON_REMOVE(attr,
'$.foodTypes[2]')
WHERE id = 1;
The JSON_REMOVE()
function is so powerful that it can be used to return a resulting JSON document after removing any JSON data (i.e. array element, object, etc.) at the specified path(s) from JSON data.
SELECT
JSON_OBJECT('name', name, 'latitude', latitude, 'longitude', longitude) AS data
FROM locations
WHERE type = 'S';
You can merge the data returned from the JSON_OBJECT()
function and merge it with existing JSON data by using the function. Notice below that you can create an entirely new JSON object, using the JSON_OBJECT()
function, and then use the JSON_MERGE()
function to combine, or merge, it with the value of the attr field.
SELECT
JSON_MERGE(
JSON_OBJECT(
'name', name,
'latitude', latitude,
'Longitude', longitude),
attr) AS data
FROM locations
WHERE type = 'R';
In MariaDB 10.6, currently the latest version, the function was added. This new function enables you to transform JSON data directly into tabular format, which can even be used directly within a FROM
clause to join to other tables (or tabular data).
SELECT l.name, d.food_type, d.menu
FROM
locations AS l,
JSON_TABLE(l.attr,
‘$’ COLUMNS(
food_type VARCHAR(25) PATH ‘$.foodType’,
menu VARCHAR(200) PATH ‘$.menu’)
) AS d
WHERE id = 2;
You can find a more detailed article on the new JSON_TABLE()
function !
Below is an example of how you can create a new CONSTRAINT
, in this case named check_attr
, that specifies that for each location of type ‘S’ the JSON data within it has to fit particular criteria. Namely you can control things like the data types for properties or values, whether a property must exist, and even the length of the values within a specified property. This is all accomplished using the JSON functions within MariaDB. As you can see it’s extremely flexible and powerful.
ALTER TABLE locations ADD CONSTRAINT check_attr
CHECK(
type != 'S' OR (type = 'S' AND
JSON_TYPE(JSON_QUERY(attr, '$.details')) = 'OBJECT' AND
JSON_TYPE(JSON_QUERY(attr, '$.details.events')) = 'ARRAY' AND
JSON_TYPE(JSON_VALUE(attr, '$.details.yearOpened')) = 'INTEGER' AND
JSON_TYPE(JSON_VALUE(attr, '$.details.capacity')) = 'INTEGER' AND
JSON_EXISTS(attr, '$.details.yearOpened') = 1 AND
JSON_EXISTS(attr, '$.details.capacity') = 1 AND
JSON_LENGTH(JSON_QUERY(attr, '$.details.events')) > 0));
Ultimately, we all learn in different ways. If you’d like to learn even more about the JSON functionality that’s available, and how you can start creating hybrid data models using MariaDB, please check out the following resources I’ve also put together.
Reminder: To get started with MariaDB (completely for free) you can , start a service using their or spin up a container from their .