Reputation: 2028
I have a table 'sometable' with a JSON field named 'jsonval', which contains a JSON object with the property 'programs' that contains an array of objects with the property 'id'
I want to search for records that contain jsonval.programs.id = 14
The following query works:
SELECT id, jsonval, JSON_EXTRACT(jsonval, '$.programs[*].id') FROM `sometable`
WHERE JSON_EXTRACT(jsonval, '$.programs[*].id') LIKE '%"14"%';
because JSON_EXTRACT(jsonval, '$.programs[*].id')
results in the string representation of the array holding the id's, i.e.: ["14","26"]
But there should be a more elegant solution, maybe using JSON_CONTAINS?
Upvotes: 2
Views: 517
Reputation: 562861
Edit: I wrote this answer before the OP revealed that they are using MariaDB 10.6, not MySQL. I'll leave it here for the benefit of readers who are using MySQL.
This is the current solution. MySQL 8.0.17 or later support the MEMBER OF
predicate.
SELECT * FROM sometable
WHERE 14 MEMBER OF (jsonval->'$.programs');
This is better than using JSON_CONTAINS() because you can create a multi-valued index on the array (also requires MySQL 8.0.17).
ALTER TABLE sometable ADD KEY ((CAST(jsonval->'$.programs' AS UNSIGNED ARRAY)));
EXPLAIN
SELECT * FROM sometable
WHERE 14 MEMBER OF (jsonval->'$.programs');
The EXPLAIN shows that it uses the index:
+----+-------------+-----------+------------+------+------------------+------------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+------------------+------------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | sometable | NULL | ref | functional_index | functional_index | 9 | const | 1 | 100.00 | Using where |
+----+-------------+-----------+------------+------+------------------+------------------+---------+-------+------+----------+-------------+
In general I think anytime you need to reference a JSON column in your WHERE clause, you're better off storing data in normal rows and columns. Writing queries for JSON data results in more complex queries and some cases cannot be optimized.
Upvotes: 3
Reputation: 5417
I think UsingJSON_CONTAINS
can make your query more explicit and potentially faster by avoiding string-based operations like LIKE.
SELECT id, jsonval
FROM sometable
WHERE JSON_CONTAINS(jsonval->'$.programs[*].id', '14');
Upvotes: 1