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

17

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_extractdans la WHEREclause, je ne peux l'utiliser que si je dis explicitement la clé du tableau dans l' json_extractargument du chemin, 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?

Klemen
la source

Réponses:

14

Une solution fournie par Morgan Tucker - @morgo est d'utiliser json_containscomme ceci:

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 hackish (voir la requête suivante) - mais je les traiterai quand j'y arriverai :)

Si je devais interroger sur une plage de dates (de 2016-04-24à 2016-04-26), je devrais ajouter un titre individuel json_containspour chaque jour dans l'intervalle de temps 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 dateclé imbriquée ailleurs

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

Klemen
la source
comme variante - définir la profondeur maximale du tableau de dates - SELECT MAX (json_depth (data - >> '$ [*]. date')), puis à travers la boucle dans l'extrait de procédure stockée vers les tables temporaires - id et date sélectionnée - sélectionnez id, json_extract ( data, "$ [0] .date") en tant que 'date' des applications, que- sélectionnez id, json_extract ( data, "$ [1] .date") en tant que 'date' des applications, etc. qu'appliquer tout le filtre et avoir la liste des identifiants
a_vlad
vous m'avez donné un indice sur la façon d'utiliser la syntaxe json_contains
Jimmy Ilenloa