您所描述的,搜索 JSON 值并返回键,就是 JSON_SEARCH() 所做的。如果您在 MySQL 中使用 JSON 数据,您应该阅读所有内置 JSON 函数的文档。没有那么多,如果您熟悉这些选择,它将为您节省很多时间。
但是,有一个警告:JSON_SEARCH() doesn't work for searching integers or booleans。它只能搜索字符串值。
这是一个演示:
mysql> select json_search(cast('{"100" : 1, "102" : 3, "103" : 3}' as json), 'all', 3) as `keys`;
+------+
| keys |
+------+
| NULL |
+------+
未找到匹配项。
但如果我将 3 值更改为字符串,它会起作用:
mysql> select json_search(cast('{"100" : 1, "102" : "3", "103" : "3"}' as json), 'all', '3') as `keys`;
+----------------------------+
| keys |
+----------------------------+
| ["$.\"102\"", "$.\"103\""] |
+----------------------------+
鉴于您的 JSON 数据存储整数值,我能想到的唯一解决方案是:
-
获取所有数据到您的客户端应用程序中,将 JSON 文档反序列化为哈希数组,然后逐一搜索。
-
创建另一个倒排索引表:
CREATE TABLE jsonkeys_by_value (
value int not null,
id int not null, -- references the primary key of your table
json_key int not null, -- references a key in the JSON document
PRIMARY KEY (value, id, json_key)
);
然后手动搜索一次所有 JSON 数据,在此表中填充对找到的每个值的每次出现的反向引用。然后就可以搜索了:
SELECT ...
FROM jsonkeys_by_value AS v
JOIN your_table_with_json AS t USING (id)
WHERE value = 3;
但这仍然不能告诉您哪些键的值为 3,只是 JSON 文档中有一个或多个值为 3 的键。至少它缩小了搜索范围,但您仍然需要使用应用程序代码检查 JSON 文档。
您也不能使用generated column,因为您说 JSON 键是可变的。
您可以使用正则表达式找出 如果 JSON 包含值 3,但这不会告诉您相应的键。 MySQL 8.0 之前没有 REGEXP_REPLACE() 函数,目前还没有基于 MySQL 8.0 的 Amazon Aurora 版本。
还有一个警告:Amazon Aurora 没有与 MySQL 5.7 完全兼容的 JSON 实施。他们在某个时候分叉了 MySQL 5.7 代码,因此他们缺少一些错误修复和功能。上次我检查时,我知道至少缺少 JSON_ARRAYAGG() 和 JSON_OBJECTAGG() 函数。这些功能是在 MySQL 5.7.22 版本中实现的,而 Aurora 没有这些功能。 Aurora 不是开源的,所以如果不仔细测试我们不知道它还缺少哪些其他功能。