MySQL doesn't have a way to index JSON documents directly, but it has given us an alternative: generated columns. By generating columns from values within a JSON document and then indexing that column, we can practically index a JSON field.
Syntax for Generated Columns
is
column_name
datatype GENERATED ALWAYS AS (expression)
You query will become like
CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`tableType` varchar(45) DEFAULT NULL,
`jkey` varchar(45) DEFAULT NULL,
`jval` json NOT NULL,
`group_virtual` VARCHAR(250) GENERATED ALWAYS AS (`jval` ->> '$.group') NOT NULL,
`user_virtual` VARCHAR(250) GENERATED ALWAYS AS (`jval` ->> '$.user') NOT NULL,
PRIMARY KEY (`id`)
);
You can check the virtual columns
SHOW COLUMNS FROM `table1`;
Field |
Type |
Null |
Key |
Default |
Extra |
id |
696e74 |
NO |
PRI |
|
|
tableType |
7661726368617228343529 |
YES |
|
|
|
jkey |
7661726368617228343529 |
YES |
|
|
|
jval |
6a736f6e |
NO |
|
|
|
group_virtual |
766172636861722832353029 |
NO |
|
|
VIRTUAL GENERATED |
user_virtual |
766172636861722832353029 |
NO |
|
|
VIRTUAL GENERATED |
if table is already created and you want to create Generated Columns, then use the following syntax
ALTER TABLE
`table1` ADD COLUMN `user_virtual` VARCHAR(250)
GENERATED ALWAYS AS(`jval` - >> '$.user') NOT NULL
AFTER `jval`;
Dont forget to index the Generated Columns
CREATE INDEX `users_idx` ON `table1`(`user_virtual`);
Then try
SHOW INDEX FROM table1;
Table |
Non_unique |
Key_name |
Seq_in_index |
Column_name |
Collation |
Cardinality |
Sub_part |
Packed |
Null |
Index_type |
Comment |
Index_comment |
Visible |
Expression |
table1 |
0 |
PRIMARY |
1 |
id |
A |
0 |
null |
null |
|
BTREE |
|
|
YES |
|
table1 |
1 |
users_idx |
1 |
user_virtual |
A |
0 |
null |
null |
|
BTREE |
|
|
YES |
|
db<>fiddle here