Veja se uma matriz JSON no MySQL contém um objeto cuja chave contém uma data específica

17

Estou tentando descobrir se existe uma linha que contém uma data específica dentro de uma matriz JSON

Digamos que meus dados sejam assim:

Aplicações de mesa:

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"}]

Como posso encontrar todos os aplicativos cujos dados contêm a data '2016-04-26'?

Então, basicamente, eu posso fazer isso:

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

Que retorna:

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"]

Mas se tentar usar json_extracta WHEREcláusula, só posso usá-la se eu disser explicitamente a chave da matriz no json_extractargumento do caminho, da seguinte maneira:

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

que retorna corretamente a linha com o ID 4.

Mas se eu tentar usar um curinga no caminho, ele não funcionará mais:

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

isso deve retornar as linhas 2, 3, 4.

Tentei muitas outras opções / variações, mas não consigo encontrar uma maneira de estruturar a consulta corretamente.

Algo assim é possível com a implementação atual do MySQL JSON?

Klemen
fonte

Respostas:

14

Uma solução fornecida por Morgan Tucker - @morgo é usar da seguinte json_containsforma:

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

Por enquanto, a resposta é boa, mas acredito que possa ter alguns problemas de desempenho e me parecer um pouco tonta (consulte a próxima consulta) - mas vou lidar com eles quando chegar lá :)

Se eu precisasse consultar um intervalo de datas (de 2016-04-24a 2016-04-26), seria necessário adicionar um inválido json_containspara cada dia no período da seguinte maneira:

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"}')

E isso retornaria dados inválidos se eu tivesse uma datechave aninhada em outro lugar

Então, se você tem uma solução diferente, eu gostaria de saber

Klemen
fonte
como variante - defina a matriz de profundidade máxima da data - SELECT MAX (json_depth (dados - >> '$ [*]. date')), do que através do loop na extração do procedimento armazenado para as tabelas temporárias - id e data selecionada - selecione id, json_extract ( data, "$ [0] .date") como 'data' dos aplicativos, que não selecione o ID, json_extract ( data, "$ [1] .date") como 'data' dos aplicativos e etc. que aplique todos os filtros e têm lista de ID
a_vlad
você me deu uma pista sobre como usar a sintaxe json_contains
Jimmy Ilenloa