Using MySQL and JSON
JSON has – over the past few months – start working its way more and more into my daily life as a web developer. I find myself using it for all sorts of solutions, whether i’m using ActionScript or PHP. For those of you who don’t know, JSON stands for JavaScript Object Notation. JSON is an extremely lightweight, human-readable and highly compacted data-interchange format. JSON works on the principle of name/value pairing, and it’s very easy to read, write and parse.
A typical JSON representation of the following PHP object would be:
{"title":"Using MySQL and JSON","date":"25 April 2009","timeOfWriting":"15h34"}
1 2 3 4 5 6 | <?php $blogPost = new stdClass(); $blogPost->title = "Using MySQL and JSON"; $blogPost->date = "25 April 2009"; $blogPost->timeOfWriting = "15h34"; ?> |
and the following ActionScript object would also be represented as it was above:
1 2 3 4 5 6 7 | var blogPost:Object = new Object(); blogPost.title = "Using MySQL and JSON"; blogPost.date = "25 April 2009"; blogPost.timeOfWriting = "15h34"; // -----or----- //var blogPost:Object = {title:"Using MySQL and JSON", date:"25 April 2009", timeOfWriting:"15h34"}; |
JSON can be extremely useful when you want to pass data from any platform to any other platform as the format is – essentially – just plain ol’ text and computers can parse JSON objects very easily.
In PHP5, this is supported natively, using the json_encode and json_decode functions.
However, in ActionScript 3.0, the parsing of JSON strings is not supported in the native ActionScript 3.0 API, so you can either write one yourself or use the JSONEncoder or JSONDecoder classes found in the as3corelib package.
Here’s how to encode/decode a JSON string in PHP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php $blogPost = new stdClass(); $blogPost->title = "Using MySQL and JSON"; $blogPost->date = "25 April 2009"; $blogPost->timeOfWriting = "15h34"; // -----or----- // $blogPost = array("title" => "Using MySQL and JSON", // "date" => "25 April 2009", // "timeOfWriting" => "15h34"); $json = json_encode($blogPost); echo "Encoded JSON: ".$json; echo "<br/>Decoded JSON (as associative array):<br/>"; print_r(json_decode($json, true)); echo "<br/>Decoded JSON (as stdClass object):<br/>"; print_r(json_decode($json)); ?> |
…and in ActionScript 3.0 using the as3corelib package:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import mx.utils.ObjectUtil; import com.adobe.serialization.json.JSONDecoder; import com.adobe.serialization.json.JSONEncoder; var blogPost:Object = new Object(); blogPost.title = "Using MySQL and JSON"; blogPost.date = "25 April 2009"; blogPost.timeOfWriting = "15h34"; // -----or----- //var blogPost:Object = {title:"Using MySQL and JSON", date:"25 April 2009", timeOfWriting:"15h34"}; var json:String = new JSONEncoder(blogPost).getString() trace("Encoded JSON: " + json); trace("Decoded JSON: " + ObjectUtil.toString(new JSONDecoder(json).getValue())); |
Now that we’ve gotten that out of the way, let’s have a look at how we can use JSON inside of MySQL. First off, let me say that i’m a big fan of structuring one’s databases correctly and not taking hideous shortcuts like i’m about to show you, but sometimes doing this hideous shortcut might actually help you develop your appplications faster, and keep things extensible.
I’ve found that i often have to keep changing my database structure when clients have changes of heart (and man, do they change them often!). It becomes extremely frustrating to have to restructure an entire database (and all associated PHP/AS3 code) every time a client remembers that he forgot about needing to store something as ridiculous the big-toe girdths of his future website’s users.
Now, i’m certainly not a patient person, and – to be honest – i don’t have time to fuck about and keep changes logic just to accomodate menial extra pieces of info. What i do therefore is usually keep a settings column in the users table, set it’s type to Text and store JSON strings in there to keep track of all the silly idiosyncratic (and sometimes idiotic) requirements of the client. Then all i have to do is parse out that string and apply some business logic to the values i find in that row under the settings column.
I find that it makes things a lot simpler and with orders of magnitude less ballaches.
What do you think?
| Print article | This entry was posted by Danny Kopping on April 25, 2009 at 4:09 pm, and is filed under ActionScript 3.0, Flex, PHP. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 2 years ago
Well most databases support XML which go against aspects atomicity and they even add extensions to access the data within the query’s conditions.
JSON, while not “supported”, has a much lighter footprint on size and parsing resource increases compared to XML. I have not used it yet however based on these facts and many others I plan to for a schema I am working on which has areas that require extensibility. Albeit not for client’s whims. Regardless, you are doing the right thing under the circumstances and keeping things simple is an important aspect of many development methodologies in use.
about 2 years ago
Hi Greg
That’s exactly right… Using JSON in MySQL is obviously not the optimal solution, but i feel that when you have a client that constantly shifts goalposts and your code is suffering from scope-creep or feature-bloat, this is the best way to solve that issue. I’ve heard of some JSON-based DBMSs but i haven’t looked into them properly.
Thanks for your comment
about 1 year ago
Json to MySQL Query Parser (Originate from Hungry Machine, Modified to add numeric extraction)
====================================
DELIMITER $$
DROP FUNCTION IF EXISTS `JSON`$$
CREATE DEFINER=`root`@`%` FUNCTION `JSON`(json TEXT, search_key VARCHAR(255)) RETURNS TEXT CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE json_length INT DEFAULT LENGTH(json);
DECLARE state ENUM(‘reading_key’,'done_reading_key’,'reading_string’, ‘reading_array’, ‘reading_number’);
DECLARE tmp_key TEXT;
DECLARE tmp_value TEXT;
DECLARE current_char VARCHAR(1);
WHILE i <= json_length DO
SET current_char = SUBSTRING(json,i,1);
IF state = 'reading_key' THEN
IF current_char = '"' THEN
SET state = 'done_reading_key';
ELSE
SET tmp_key = CONCAT(tmp_key, current_char);
END IF;
ELSEIF state = 'done_reading_key' THEN
IF current_char = '"' THEN
SET state = 'reading_string';
ELSEIF current_char = '[' THEN
SET state = 'reading_array';
ELSEIF IsNumeric(current_char)=1 THEN
SET state = 'reading_number';
SET tmp_value=CONCAT(tmp_value, SUBSTRING(json,i,1));
END IF;
ELSEIF state = 'reading_string' OR state = 'reading_array' THEN
IF current_char = '\\' THEN
SET i = i + 1;
SET tmp_value = CONCAT(tmp_value, SUBSTRING(json,i,1));
ELSEIF (state = 'reading_string' AND current_char = '"') OR (state = 'reading_array' AND current_char = ']') THEN
IF search_key = tmp_key THEN
RETURN tmp_value;
ELSE
SET state = NULL;
END IF;
ELSE
SET tmp_value = CONCAT(tmp_value, current_char);
END IF;
ELSEIF (state = 'reading_number') THEN
IF (state = 'reading_number' AND isNumeric(current_char)!=1) THEN
IF search_key = tmp_key THEN
RETURN tmp_value;
ELSE
SET state = NULL;
END IF;
ELSE
SET tmp_value=CONCAT(tmp_value, SUBSTRING(json,i,1));
END IF;
ELSE
IF current_char='"' THEN
SET state = 'reading_key';
SET tmp_key = '';
SET tmp_value = '';
END IF;
END IF;
SET i = i + 1;
END WHILE;
RETURN NULL;
END$$
DELIMITER ;
about 1 year ago
If you have to store data structeres that are not fixed and can change frequently, relational databases (as MySQL) is not the best solution.
You could try some document based database as CouchDB or MongoDB to store the unstructured data.
about 11 months ago
I agree. Lotus Notes uses a similar philosophy, if not technology, and whatever its other failings, it is great way to prototype a design right in front of the client for immediate feed-back.
I am working on a PHP class to graciously handle whatever name/data type thrown at it. I too want to be able to respond to client requests as soon as possible, and then clean up and optimize later. That toe-size field that appears out of the blue is a likely candidate for deletion when the project reaches the real-world. Why waste time on it twice?
I don’t want a free-form data structure to continue forever, just long enough to get things working with real-world data so I can see what’s actually being queried, how often, and how big everything really is. Then, where appropriate, I can create more efficient fields and indexes and port the data over in a grand clean-up that is (hopefully) transparent to higher-level code.
My only question is, is JSON the best way to encode/decode? It looks good for the simple number and text fields I am handling now, but some day I might want my class to handle some bizarre data structure, and I don’t want it to choke.
about 11 months ago
Hey Dave – thanks for the comment.
I feel that JSON is the best way to do it – if you have to resort to this; JSON can represent complex data and there are some insanely fast serializers/deserializers out there for JSON