MySQL - 按数组中的 JSON 值排序元素?

MySQL - Order elements by JSON value in array?

嘿,我整天都在搜索和寻找。进一步了解我的问题和选择。我缺乏理解。

我的一般问题是,我正在尝试根据 JSON 中的值 SELECT 行,并根据所选值对选择进行排序。

我有一个 table(元素),有两列:Person 和 Tags。标签包含一个 JSON 数组,其中可以包含多个 JSON 对象。对象总是有 "name" 和 "sort"。

    +-------------+------------------------------------------------------------------+
    | Person      | tags                                                       
    +-------------+------------------------------------------------------------------+
    | William     | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}]      
    | Anna        | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}]       
    | Michael     | [{"name": "apple", "sort": "2"}]                                     
    +-------------+------------------------------------------------------------------+

理想情况下,我想做的是告诉数据库使用 SELECT * FROM elements WHERE 标签(有一个名称为 "apple" 的对象) ORDER by(对象的排序值它匹配的地方);

所以如果我给它 "apple" 它会列出:William、Michael、Anna。

如果我给它 "orange" 它会列出:Anna, William。

我一直在研究在 SELECTs(子查询)中使用 SELECTs,但我可以找到与 JSON 的正确组合。下面是我得到的最接近的,但我可以看出它需要更高级的东西?

SELECT * 
FROM elements 
WHERE JSON_SEARCH( tags, 'one', 'apple', NULL, '$[*].name' ) IS NOT NULL

这将 return 所有带有 apple 标签的人,但它不会根据排序对他们进行排序。

欢迎提出任何建议,在此先感谢。

有一个类似的问题here可能会对您有所帮助。

您可以使用 JSON_EXTRACT,但它会变得复杂,因为您要存储一个 JSON 数据数组,因此您可能还需要一个子查询。

不过我会提出替代解决方案。您是否考虑过跨多个 table 重组您的数据库而不是使用 JSON blob?

你可以有一个 table 专用于存储标签,像这样:

+-------------+------------------------------------------------------------------+
| tagid       | name                                                       
+-------------+------------------------------------------------------------------+
| 1           | apple     
| 2           | orange       
| 3           | banana                                   
+-------------+------------------------------------------------------------------+

另一个table用来存储人:

+-------------+------------------------------------------------------------------+
| id          | name                                                       
+-------------+------------------------------------------------------------------+
| 1           | William      
| 2           | Anna      
| 3           | Michael                                     
+-------------+------------------------------------------------------------------+

最后一个 table 用于存储人与标签之间的多对多关系。这也是您可以存储排序顺序的地方:

+-------------+--------------+-----------+--------------------------------------+
| id          | personid     | tagid     | sort                                          
+-------------+--------------+-----------+--------------------------------------+
| 1           | 1            | 1         | 1
| 2           | 1            | 2         | 2
| 3           | 2            | 1         | 3  
| 4           | 2            | 2         | 1
| 5           | 3            | 1         | 1                             
+-------------+--------------+-----------+---------------------------------------+

看起来更像这样的数据库模型将使复杂的查询变得更加简单,并且不需要复杂的子查询,只需要连接。如果这对您很重要,它可能会提高您报告与标签相关的数据的能力。

这里有一个适合您的 "nice" 查询。您只需将查询的 res.* 更改为 res.name。

SELECT res.* FROM (
    SELECT 
        SUBSTRING_INDEX( JSON_UNQUOTE (JSON_SEARCH(e.tags, 'one', 'apple')),'.',1) as idx
        ,e.* FROM `elements` AS e ) AS res
 WHERE res.idx IS NOT NULL
 ORDER BY JSON_UNQUOTE(JSON_EXTRACT(res.tags,CONCAT(res.idx,'.sort')));

样本

mysql> select * from elements;
+----+---------+-------------------------------------------------------------------+
| id | Person  | tags                                                              |
+----+---------+-------------------------------------------------------------------+
|  1 | William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}] |
|  2 | Anna    | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}] |
|  3 | Michael | [{"name": "apple", "sort": "2"}]                                  |
+----+---------+-------------------------------------------------------------------+
3 rows in set (0.00 sec)

找苹果

    mysql> SELECT res.* FROM (
        -> SELECT 
        -> SUBSTRING_INDEX( JSON_UNQUOTE (JSON_SEARCH(e.tags, 'one', 'orange')),'.',1) as idx
        -> ,e.* FROM `elements` AS e ) AS res
        ->  WHERE res.idx IS NOT NULL
        ->  ORDER BY JSON_UNQUOTE(JSON_EXTRACT(res.tags,CONCAT(res.idx,'.sort')));
+----+---------+-------------------------------------------------------------------+
| id | Person  | tags                                                              |
+----+---------+-------------------------------------------------------------------+
|  1 | William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}] |
|  2 | Anna    | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}] |
|  3 | Michael | [{"name": "apple", "sort": "2"}]                                  |
+----+---------+-------------------------------------------------------------------+
3 rows in set (0.00 sec)

寻找橙色

mysql> SELECT res.* FROM (
    -> SELECT 
    -> SUBSTRING_INDEX( JSON_UNQUOTE (JSON_SEARCH(e.tags, 'one', 'orange')),'.',1) as idx
    -> ,e.* FROM `elements` AS e ) AS res
    ->  WHERE res.idx IS NOT NULL
    ->  ORDER BY JSON_UNQUOTE(JSON_EXTRACT(res.tags,CONCAT(res.idx,'.sort')));
+------+----+---------+-------------------------------------------------------------------+
| idx  | id | Person  | tags                                                              |
+------+----+---------+-------------------------------------------------------------------+
| $[1] |  2 | Anna    | [{"name": "apple", "sort": "3"}, {"name": "orange", "sort": "1"}] |
| $[1] |  1 | William | [{"name": "apple", "sort": "1"}, {"name": "orange", "sort": "2"}] |
+------+----+---------+-------------------------------------------------------------------+
2 rows in set (0.01 sec)