web-dev-qa-db-fra.com

Voir si un tableau JSON dans MySQL contient un objet dont la clé contient une date spécifique

j'essaie de savoir s'il y a une ligne qui contient une date spécifique à l'intérieur d'un tableau JSON

Disons que mes données ressemblent à ceci:

Applications de table:

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

Comment trouver toutes les applications dont les données contiennent la date '2016-04-26'?

Donc, fondamentalement, je peux le faire:

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

Qui retourne:

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

Mais si j'essaie d'utiliser json_extract Dans la clause WHERE, je ne peux l'utiliser que si je dis explicitement la clé du tableau dans l'argument path de json_extract, Comme ceci:

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

qui renvoie correctement la ligne avec l'ID 4.

Mais si j'essaie d'utiliser un caractère générique dans le chemin, cela ne fonctionne plus:

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

cela devrait renvoyer les lignes 2, 3, 4.

J'ai essayé de nombreuses autres options/variantes mais je n'arrive pas à trouver un moyen de structurer correctement la requête.

Est-ce que quelque chose comme ça est même possible avec l'implémentation actuelle de MySQL JSON?

18
Klemen

Une solution fournie par Morgan Tucker - @morgo consiste à utiliser json_contains ainsi:

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

Pour l'instant, la réponse est OK, mais je pense que cela peut avoir des problèmes de performances et me semble un peu hack (voir la requête suivante) - mais je traiterai ceux-ci lorsque j'y serai :)

Si je dois interroger une plage de dates (de 2016-04-24 à 2016-04-26) J'aurais besoin d'ajouter un _ json_contains pour chaque jour de la période comme suit:

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

Et cela retournerait des données invalides si j'avais une clé date imbriquée ailleurs

Donc, si vous avez une solution différente, j'aimerais savoir

15
Klemen