I understand that it is generally considered a "bad idea" to store JSON in a MySQL column due to the fact that it becomes difficult to maintain and is not easily searched, or otherwise queried. However, I feel that the scenario I have encountered in my application is a reasonable use case for storing JSON data in my MySQL table. I am indeed looking for an answer, particularly one that may point out any difficulties which I may have overlooked, or if there is any good reason to avoid what I have planned and if so, an alternate approach.
The application at hand provides resource and inventory management, and supports building Assemblies, which may contain an infinite number of sub assemblies.
I have a table which holds all of the metadata for items, such as their name, sku, retail price, dimensions, and most importantly to this question: the item type. An item can either be a part or an assembly. For items defined as assemblies, their contents are stored in another table, item_assembly_contents
whose structure is rather expected, using a parent_id
column to link the children to the parent. As you may expect, at any time, a user may decide to add or remove an item from an assembly, or otherwise modify the assembly contents or delete it entirely.
Here is a visual representation of the above table description, populated with data that when composed, creates an assembly containing another assembly.
With the above structure, any item that is deleted from the
items
table will also be automatically deleted in the item_assembly_contents
table via InnoDB ON DELETE CASCADE
.
Here is a very simple example Assembly in JSON format, demonstrating a single Sub Assembly structure.
{
"id":1,
"name":"Fruit Basket",
"type":"assembly",
"contents":[
{
"id":10,
"parent_id":1,
"name":"Apple",
"type":"part",
"quantity":1
},
{
"id":11,
"parent_id":1,
"name":"Orange",
"type":"part",
"quantity":1
},
{
"id":12,
"parent_id":1,
"name":"Bag-o-Grapes",
"type":"assembly",
"quantity":1,
"contents":[
{
"id":100,
"parent_id":12,
"name":"Green Grape",
"quanity":10,
"type":"part"
},
{
"id":101,
"parent_id":12,
"name":"Purple Grape",
"quanity":10,
"type":"part"
}
]
}
]
}
The Fruit Basket is an Assembly, which contains a Sub-Assembly named "Bag o Grapes". This all works wonderfully, until orders and shipments come into consideration.
Take for example, an outbound shipment containing an assembly. At any time, the user must be able to see the contents of the assembly, as they were defined at the time of shipment, which rules out simply retrieving the data from the items
and item_assembly_contents
table, as these tables may have been modified since the shipment was created. Therefore, assembly contents must be explicitly saved with the shipment so that they may be viewed at a later date, independent of the state or mere existence of the assembly in the user's defined inventory (that being, the items
table).
It is storing the assembly contents along side the shipment contents that has me a bit confused, and where it seems to me that storing the data in JSON is a visable solution. It is critical to understand the following points about this data:
See this image for a (hopefully) more clear visualization of the data:
Questions
As always, thank you so much for your time and please do not hesitate to request clarification or additional information.
UPDATE
As per @Rowland Shaw's suggestion (below), I've come up with another proposed table structure using a reflexive or "bunny ear" relationship to the order_assembly_contents table. Please see the following image:
I feel this is a lot more elegant than storing the JSON directly, as the data is more relational and database friendly. Retrieving the data and forming it for the client should be easy-peasy as well! Please provide any input on the above structure!
Typically, for an ordering system I'd expect something like
Product -< OrderLine >- Order
In your case, you could add a "bunny ear" relation on your Product to refer to itself. So your outbound_shipment_contents
loses name
, type
to the new product
. You can then recursively build up the tree of items to pick as required.