Посмотрите, содержит ли массив JSON в MySQL объект, ключ которого содержит конкретную дату

17

я пытаюсь выяснить, есть ли строка, которая содержит конкретную дату в массиве JSON

Допустим, мои данные выглядят так:

Настольные приложения:

id | application_id | data
# Rows
1 | 1 | [{"data" : ["some", "data#1"], "date": "2016-04-21"}, {"data" : ["other", "data#1"], "date" : "2016-04-22"}]
2 | 2 | [{"data" : ["some", "data#2"], "date": "2016-04-21"}, {"data" : ["other", "data#2"], "date" : "2016-04-26"}]
3 | 1 | [{"data" : ["some", "data#3"], "date": "2016-04-22"}, {"data" : ["other", "data#3"], "date" : "2016-04-26"}]
4 | 3 | [{"data" : ["some", "data#4"], "date": "2016-04-26"}]

Как я могу найти все приложения, данные которых содержат дату '2016-04-26'?

В общем, я могу сделать это:

select id, json_extract(`data`, "$[*].date") from applications

Который возвращает:

1 | ["2016-04-21", "2016-04-22"]
2 | ["2016-04-21", "2016-04-26"]
3 | ["2016-04-22", "2016-04-26"]
4 | ["2016-04-26"]

Но если попытаться использовать json_extractв WHEREпредложении, я могу использовать его, только если я явно сообщу ключ массива в json_extractаргументе пути, например, так:

select * from applications where json_extract(`data`, "$[0].date") = "2016-04-26"

который правильно возвращает строку с идентификатором 4.

Но если я попытаюсь использовать подстановочный знак в пути, он больше не работает:

select * from applications where json_extract(`data`, "$[*].date") = "2016-04-26"

это должно вернуть строки 2, 3, 4.

Я пробовал много других вариантов / вариантов, но я не могу найти способ правильно структурировать запрос.

Возможно ли что-то подобное в текущей реализации MySQL JSON?

Klemen
источник

Ответы:

14

Морган Такер - @morgo предлагает одно решение json_contains:

select * from applications where json_contains(`data`, '{"date" : "2016-04-26"}')

Пока что ответ хороший, но я считаю, что он может иметь некоторые проблемы с производительностью и кажется мне немного хакерским (см. Следующий запрос) - но я буду иметь дело с ними, когда доберусь туда :)

Если мне нужно будет выполнить запрос в диапазоне дат (от 2016-04-24до 2016-04-26), мне нужно будет добавить инвидимум json_containsдля каждого дня во временном интервале, например, так:

select * from applications where json_contains(`data`, '{"date" : "2016-04-26"}') or json_contains(`data`, '{"date" : "2016-04-25"}') or json_contains(`data`, '{"date" : "2016-04-24"}')

И это вернуло бы неверные данные, если бы у меня был dateключ, вложенный куда-то еще

Так что, если у вас есть другое решение, я хотел бы знать,

Klemen
источник
как вариант - определить максимальную глубину массива даты - SELECT MAX (json_depth (data - >> '$ [*]. date')), чем через цикл извлечения хранимой процедуры во временные таблицы - id и выбранную дату - выбрать id, json_extract ( data, «$ [0] .date») в качестве «даты» из приложений, затем выберите id, json_extract ( data, «$ [1] .date») в качестве «даты» из приложений и т. д., к которым применяется весь фильтр и есть список идентификаторов
a_vlad
Вы дали мне подсказку о том, как использовать синтаксис json_contains
Джимми Иленлоа