Modifier des données JSON dans Postgres et Hibernate 6

Voici un autre article de la série relative à la prise en charge des fonctions JSON de Postgres dans un projet utilisant le Hibernate framework avec la version 6. Le sujet de l’article est les opérations de modification sur les enregistrements JSON. Comme dans l’article précédent, il convient de mentionner que Postgres ne dispose peut-être pas d’opérations aussi complètes que d’autres bases de données NoSQL telles que MongoDB pour la modification JSON (bien que, avec les constructions de fonctions appropriées, il soit possible d’obtenir le même effet). Il convient toujours à la plupart des projets qui nécessitent une modification JSON. De plus, avec la prise en charge des transactions (qui n’est pas prise en charge à un tel niveau dans une base de données NoSQL), c’est une très bonne idée d’utiliser Postgres avec des données JSON. Bien sûr, les bases de données NoSQL ont d’autres avantages qui pourraient convenir à de meilleurs projets.

Il existe généralement de nombreux articles sur le support de Postgres pour JSON. Cet article se concentre sur l’intégration de ce support avec la bibliothèque Hibernate 6.

Si quelqu’un est intéressé par l’interrogation de données JSON ou la recherche de texte à l’aide de Postgres et d’Hibernate, veuillez consulter les liens ci-dessous:

Données de test

Pour l’article, supposons que notre base de données contienne une table appelée item, qui a une colonne avec du contenu JSON, comme dans l’exemple ci-dessous :

SQL

 

Nous avons également peut-être certaines données de test :

SQL

 

Exécution SQL native

Comme dans d’autres frameworks Java, avec Hibernate, vous pouvez exécuter des requêtes SQL native — ce qui est bien documenté et il existe beaucoup d’exemples sur Internet. C’est pourquoi dans cet article, nous ne focuserons pas sur l’exécution des opérations d’opérations SQL native. Cependant, il y aura des exemples de quelle sorte de SQL les opérations JPA génèrent. Comme Hibernate est une implémentation de JPA, il convient de montrer comment l’API JPA peut modifier les données JSON dans la base de données Postgres.

Modifier les propriétés de l’objet JSON et non l’objet JSON entier (chemin)

Définir l’ensemble du chargement JSON pour une colonne est facile et n’exige pas beaucoup d’explication. Nous définissons simplement la valeur de la propriété dans notre classe Entity, qui représente une colonne avec du contenu JSON.

Il est similaire à définir une ou plusieurs propriétés JSON pour une seule ligne de base de données. Nous lisons simplement la ligne de table, déserialisons la valeur JSON en un POJO représentant un objet JSON, définissons les valeurs pour les propriétés spécifiques et mettons à jour les enregistrements de base de données avec le chargement entier. Cependant, une telle approche peut ne pas être pratique lorsque nous voulons modifier les propriétés JSON pour plusieurs lignes de base de données.

Supposons qu’il soit nécessaire de faire des mises à jour en lot des propriétés JSON spécifiques. S’abonner à la base de données et de mettre à jour chaque enregistrement peut ne pas être une méthode efficace.

Il serait beaucoup plus efficace de faire une telle mise à jour avec une seule instruction update où nous définissons les valeurs pour les propriétés JSON spécifiques. Heureusement, Postgres dispose de fonctions qui modifient le contenu JSON et peuvent être utilisées dans l’instruction SQL de mise à jour.

Posjsonhelper

Hibernate offre un meilleur support pour la modification de JSON dans la version 7, incluant la plupart des fonctions et opérateurs mentionnés dans cet article. Cependant, il n’y a pas de plans pour ajouter de support de cette nature dans la version 6. Heureusement, le projet Posjsonhelper ajoute de tellesfonctionnalitéspour Hibernate dans la version 6. Tous les exemples ci-dessous utiliseront la bibliothèque Posjsonhelper.Veuillez consulter celienpour savoir comment joindre une bibliothèque à votre projet Java. Vous devrez également joindre FunctionContributor.

Tous les exemples utilisent la classe d’entité Java qui représente le tableau item, dont la définition a été mentionnée ci-dessus:

Java

 

jsonb_set Function Wrapper

La fonction jsonb_set est probablement la fonction la plus utile lorsqu’il est nécessaire de modifier des données JSON. Elle permet de définir des propriétés spécifiques pour les objets JSON et des éléments de tableau spécifiques en fonction de l’index du tableau.

Par exemple, le code ci-dessous ajoute la propriété "birthday" à la propriété interne "child".

Java

 

Ce code générerait une telle instruction SQL:

SQL

 

Enveloppe de l’opérateur de concaténation « || »

L’enveloppe de l’opérateur de concaténation (||) concatène deux valeurs JSONB en une nouvelle valeur JSONB.

Selon la documentation Postgres, le comportement de l’opérateur est le suivant:

La concaténation de deux tableaux génère un tableau contenant tous les éléments de chaque entrée. La concaténation de deux objets génère un objet contenant l’union de leurs clés, en prenant la valeur du second objet lorsqu’il y a des clés dupliquées. Tous les autres cas sont traités en convertissant une entrée qui n’est pas un tableau en un tableau à un seul élément, puis en procédant de la même manière que pour deux tableaux. Ne fonctionne pas de manière récursive : seule la structure de tableau ou d’objet de niveau supérieur est fusionnée.

Voici un exemple d’utilisation de ce wrapper dans votre code:

Java

 

Code fusionner un objet JSON avec la propriété child avec l’objet JSON déjà stocké dans la base de données.

Ce code génère une requête SQL de ce type :

SQL

 

Supprimer l’élément du champ ou de l’arrêt basé sur l’index à la chemin spécifié « #-« 

Le Posjsonhelper dispose d’une enveloppe pour l’opération de suppression (#-). Elle supprime le champ ou l’élément de l’arrêt basé sur l’index à la chemin spécifié, où les éléments de chemin peuvent être soit les clés de champs soit les indexs d’arrêts. Par exemple, le code ci-dessous supprime de l’objet JSON en fonction du chemin JSON "child.pets".

Java

 

La requête SQL générée serait :

SQL

 

Supprimer plusieurs éléments de l’arrêt à la chemin spécifié

Par défaut, Postgres (au moins dans la version 16) ne dispose pas de fonction intégrée permettant la suppression d’éléments de l’arrêt en fonction de leur valeur. Cependant, il dispose de l’opérateur intégré -#, que nous avons mentionné ci-dessus, qui aide à supprimer les éléments de l’arrêt en fonction de leur index et non de leur valeur.

Au titre de cette fonctionnalité, le Posjsonhelper peut générer une fonction qui doit être ajoutée à l’opération DDL et exécutée sur votre base de données.

SQL

 

L’une des enveloppes utilisera cette fonction pour permettre la suppression de plusieurs valeurs de l’arrêt JSON. Ce code supprime les éléments "mask" et "compass" pour la propriété "child.inventory".

Java

 

Voici la requête SQL générée par le code ci-dessus :

SQL

 

Hibernate6JsonUpdateStatementBuilder : comment combiner plusieurs opérations de modification dans une seule requête UPDATE.

Tous les exemples précédents ont montré l’exécution d’une seule opération modifiant des données JSON. Bien sûr, nous pouvons avoir des instructions de mise à jour dans notre code qui utilisent plusieurs des wrappers mentionnés dans cet article ensemble. Cependant, être conscient de la manière dont ces opérations et fonctions seront exécutées est crucial parce qu’il est plus logique que le résultat de la première opération de modification de JSON soit un input pour les opérations de modification de JSON suivantes. Le sortie de cette opération serait un input pour l’opération suivante, et ainsi de suite, jusqu’à la dernière opération de modification de JSON.

Pour mieux illustrer cela, vérifiez le code SQL.

SQL

 

Cela suppose que nous avons quatre exécutions de la fonction jsonb_set et deux opérations delete. L’opération la plus imbriquée delete est la première opération de modification de JSON parce que la valeur originale d’une colonne stockant des données JSON est passée en paramètre.

Bien que cette approche soit correcte, et que le wrapper existant permette la création de telles instructions UPDATE, elle peut ne pas être lisible d’un point de vue de code. Heureusement, Posjsonhelper dispose d’un composant constructeur qui facilite la construction de telles instructions complexes.

Le type Hibernate6JsonUpdateStatementBuilder permet la construction d’instructions de mise à jour avec plusieurs opérations modifiant le JSON et dépendantes l’une de l’autre.

Voici un exemple de code :

Java

 

Le statement SQL mentionné précédemment a été généré par ce code.

Pour en savoir plus sur la manière dont le constructeur fonctionne, veuillez consulter la documentation.

Conclusion

La base de données Postgres offre une large gamme de possibilités en ce qui concerne les opérations de modification de données JSON. Cela nous amène à considérer Postgres comme une bonne solution de stockage de documents. Ainsi, si notre solution n’exige pas de meilleures performances de lecture, une meilleure échelle ou un sharding (bien que tout cela puisse être réalisé avec la base de données Postgres, en particulier avec les solutions fournies par les fournisseurs de cloud tels que AWS), alors il vaut la peine de considérer la stockage de vos documents JSON dans la base de données Postgres — sans oublier le soutien des transactions avec des bases de données telles que Postgres.

Source:
https://dzone.com/articles/modify-json-data-in-postgres-and-hibernate