'MySQL JSON - using IN statement | json_contains
I'm trying to select all columns where the roles property in the json column contains ANY of the values.
Statements I've tried:
SELECT * FROM components WHERE json->'$.roles' IN(1)
- this doesn't even work but it should in my opinion...
SELECT * FROM components WHERE JSON_CONTAINS(components, '1', '$.roles')
- this does work however is strict, so when I use
1it pulls both like it should because they both contain 1, however if I insert1,2orJSON_ARRAY(1,2)it will only pull the later row because it isn't checking per array element...
I have the following table components structure and data:
+====+========================================================================================================================================================================================================+==+
| id | json | |
+====+========================================================================================================================================================================================================+==+
| 1 | {"area": 1, "roles": [1], "elements": [{"home": {"content": "Home", "attributes": {"class": "my_class_1"}}}, {"dashboard": {"content": "Dashboard", "attributes": {"class": "my_class_1"}}}]} | |
+----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--+
| 2 | {"area": 1, "roles": [1, 2, 5], "elements": [{"home": {"content": "Testing", "attributes": {"class": "my_class_1"}}}, {"dashboard": {"content": "Dashboard", "attributes": {"class": "my_class_1"}}}]} | |
+----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--+
Question: How can I modify either of these statements to allow them to query the rows based on the values in the roles property?
Solution 1:[1]
See https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-overlaps
JSON_OVERLAPS(json_doc1, json_doc2)
Compares two JSON documents. Returns true (1) if the two document have any key-value pairs or array elements in common. If both arguments are scalars, the function performs a simple equality test.
This function serves as counterpart to JSON_CONTAINS(), which requires all elements of the array searched for to be present in the array searched in. Thus, JSON_CONTAINS() performs an AND operation on search keys, while JSON_OVERLAPS() performs an OR operation.
Queries on JSON columns of InnoDB tables using JSON_OVERLAPS() in the WHERE clause can be optimized using multi-valued indexes. Multi-Valued Indexes, provides detailed information and examples.
When comparing two arrays, JSON_OVERLAPS() returns true if they share one or more array elements in common, and false if they do not.
mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]");
+---------------------------------------+
| JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]") |
+---------------------------------------+
| 1 |
+---------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]");
+---------------------------------------+
| JSON_OVERLAPS("[1,3,5,7]", "[2,6,7]") |
+---------------------------------------+
| 1 |
+---------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]");
+---------------------------------------+
| JSON_OVERLAPS("[1,3,5,7]", "[2,6,8]") |
+---------------------------------------+
| 0 |
+---------------------------------------+
1 row in set (0.00 sec)
Solution 2:[2]
try one of these it should work
SELECT * FROM components WHERE JSON_CONTAINS([1], roles, '$');
SELECT * FROM components WHERE JSON_CONTAINS([1], CAST(roles as JSON), '$');
Solution 3:[3]
Just tried because i got a similar issue, and the following works for me:
field->'$.sub' REGEXP '^(1|3|5)$'
Yes, it seems that it is possible to use regular expressions here...
Note that if you try to query a string field in the json you should considder that strings are surrounded by a ", so you have to query something like this:
customer->'$.mail' REGEXP '^\"(info|contact)@.*\.com\"$'
Hope it helps, but i dont know how that impacts in performance...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alexey Kosov |
| Solution 2 | |
| Solution 3 | dkr8 |
