Запросы в многоуровневом JSON в MariaDB / MySQL для конкретного значения - PullRequest
1 голос
/ 25 марта 2019

Я работаю с таблицей MariaDB, в которой значение JSON хранится следующим образом:

{"nextValue":4,"1":{"text":"Item1","textDisplay":"","value":1,"isActive":0},"2":{"text":"Item2","textDisplay":"","value":2,"isActive":1},"3":{"text":"Item3","textDisplay":"","value":3,"isActive":1}}

То, что я пытаюсь сделать, - это создать запрос, в котором у меня может быть столбец, который в качестве элемента, т. Е. «Item2» и в следующем столбце будет иметь значение для ключа «value» из этого JSON. Итак, если «Item2» вернется, в столбце рядом с ним будет «2».

Я перепробовал многие опции JSON, доступные для MariaDB, но я просто не могу понять, как это сделать.

1 Ответ

2 голосов
/ 26 марта 2019

Я протестировал следующее с MySQL 8.0. Он использует функции, которые, по-видимому, присутствуют в MariaDB согласно его документации, но у меня нет экземпляра MariaDB для тестирования.

SELECT * FROM mytable;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| data                                                                                                                                                                                                                               |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| {"1": {"text": "Item1", "value": 1, "isActive": 0, "textDisplay": ""}, "2": {"text": "Item2", "value": 2, "isActive": 1, "textDisplay": ""}, "3": {"text": "Item3", "value": 3, "isActive": 1, "textDisplay": ""}, "nextValue": 4} |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

SELECT JSON_UNQUOTE(JSON_EXTRACT(JSON_EXTRACT(data, REPLACE(JSON_UNQUOTE(JSON_SEARCH(data, 'one', 'Item2')), '.text', '')), '$.value')) AS value FROM mytable;
+-------+
| value |
+-------+
| 2     |
+-------+

Это невероятно хрупкий процесс, основанный на замене строк в путях JSON и последующем использовании этих путей в дальнейших функциях JSON. Разработка и поддержка таких сложных операторов SQL потребует у вашего работодателя много рабочих часов.

Альтернативой может быть обновление до MySQL 8.0 и использование функции JSON_TABLE () для отображения вашего документа JSON в производную таблицу, тогда вы можете использовать условия в предложении WHERE.

SELECT j.* FROM mytable2, 
JSON_TABLE(mytable2.data, '$[*]' 
  COLUMNS (
    rowid FOR ORDINALITY,
    `text` VARCHAR(20) PATH '$.text',
    textDisplay TEXT PATH '$.textDisplay',
    value INT PATH '$.value',
    isActive BOOL PATH '$.isActive'
  )
) AS j

+-------+-------+-------------+-------+----------+
| rowid | text  | textDisplay | value | isActive |
+-------+-------+-------------+-------+----------+
|     1 | Item1 |             |     1 |        0 |
|     2 | Item2 |             |     2 |        1 |
|     3 | Item3 |             |     3 |        1 |
+-------+-------+-------------+-------+----------+

Но это не сработает с данными JSON, которые у вас есть, потому что функция работает, только если ваш JSON является массивом, тогда как ваши данные отформатированы как объект JSON. Приведенный выше пример работал, только когда я изменил формат данных JSON на массив:

select * from mytable2;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| data                                                                                                                                                                                                |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| [{"text": "Item1", "value": 1, "isActive": 0, "textDisplay": ""}, {"text": "Item2", "value": 2, "isActive": 1, "textDisplay": ""}, {"text": "Item3", "value": 3, "isActive": 1, "textDisplay": ""}] |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Формат JSON, разработанный вашими разработчиками, позволяет им легко вставлять данные, но это совершенно бесплатное использование JSON и делает запросы к данным излишне сложными. Это пример эффекта внутренней платформы :

Эффект внутренней платформы - это тенденция архитекторов программного обеспечения создавать систему, настраиваемую так, чтобы она стала копией, а часто и плохой копией платформы разработки программного обеспечения, которую они используют. Как правило, это неэффективно, и такие системы часто считаются примерами анти-паттерна.

Как я уже говорил выше, я бы разработал это как обычную таблицу SQL:

CREATE TABLE Items (
  id INT AUTO_INCREMENT PRIMARY KEY,
  `text` VARCHAR(20), 
  textDisplay TEXT, 
  value INT, 
  isActive BOOL
);

Заполните его значениями в каждом столбце:

INSERT INTO Items 
VALUES (1, 'Item1', '', 1, 0),
       (2, 'Item2', '', 2, 1),
       (3, 'Item3', '', 3, 1);

Тогда вы можете запросить его очень просто:

SELECT value FROM Items WHERE `text` = 'Item2';
+-------+
| value |
+-------+
|     2 |
+-------+

Ваш работодатель должен предпочесть простоту хранения данных обычным способом, потому что он сэкономит много времени и денег, когда придет время запрашивать данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...