Wijzigen JSON-gegevens in Postgres en Hibernate 6

Dit is een ander artikel in de reeks die gerelateerd is aan het ondersteunen van Postgres JSON-functies in een project dat de Hibernate framework gebruikt met versie 6. Het thema voor het artikel is de aanpassingsbewerkingen op JSON-records. Net zoals in het vorige artikel, is het waard om te vermelden dat Postgres misschien nu zo uitgebreide bewerkingen als andere NoSQL-databassen zoals MongoDB voor JSON-bewerking heeft ( hoewel het met de juiste functieconstructies mogelijk is om hetzelfde effect te behalen). Het is nog steeds geschikt voor de meeste projecten die JSON-bewerking nodig hebben. Bovendien, met ondersteuning voor transacties ( die niet beschikbaar is in een NoSQL-databank op zo’n niveau), is het een goed idee om Postgres te gebruiken met JSON-gegevens. Natuurlijk hebben NoSQL-databassen andere voordelen die misschien beter aan projecten passen.

Er zijn er in het algemeen veel artikelen over de ondersteuning vanJSON door Postgres. Dit artikel focus op het integreren van deze ondersteuning met de Hibernate 6-bibliotheek. 

Voor wie geïnteresseerd is in het opsporen van JSON-gegevens of tekstzoeken met behulp van Postgres en Hibernate, zie de onderstaande koppelingen:

Testgegevens

Voor het artikel, stel dat onze database een tabel heet genaamd item heeft, die een kolom bevat met JSON-inhoud, zoals in het onderstaande voorbeeld:

SQL

 

We hebben misschien ook enkele testgegevens:

SQL

 

Natieve SQL-uitvoering

Net zoals in andere Java-frameworks, kan je met Hibernate ook native SQL-query’s uitvoeren — wat goed gedocumenteerd is en veel voorbeelden op het internet te vinden zijn. Daarom zal dit artikel niet focus leggen op de uitvoering van native SQL-operaties. Er zal echter wel een voorbeeld zijn van welke soort SQL de JPA-operaties genereren. want Hibernate is een JPA-implementatie, het maakt zin om te laten zien hoe de JPA-API JSON-gegevens in de Postgres-database kan wijzigen.

Wijzigen van JSON-objecteigenschappen en niet het gehele JSON-object (pad)

Het instellen van het gehele JSON-payload voor één kolom is gemakkelijk en vereist niet veel uitleg. We stellen de waarde voor de eigenschap in onze Entity-klasse, die een kolom met JSON-inhoud representeert.

Het is vergelijkbaar met het instellen van een enkele of meerdere eigenschappen voor JSON voor één databaseregel. We lezen gewoon de tabelregel in, deserialiseren de JSON-waarde naar een POJO dat een JSON-object weergeeft, stellen waarden voor bepaalde eigenschappen in en update de databaserecords met het gehele payload. Het is echter misschien niet praktisch als we JSON-eigenschappen willen wijzigen voor meerdere databaseregels.

Veronderstel dat we een batch-update moeten uitvoeren op bepaalde JSON-eigenschappen. Het halen van informatie uit de database en het bijwerken van elk record kan niet de effectiefste methode zijn.

Het zou veel beter zijn om zo’n update uit te voeren met één update-instructie waarin we waarden instellen voor bepaalde JSON-eigenschappen. gelukkig heeft Postgres functies die JSON-inhoud wijzigen en die kunnen worden gebruikt in de SQL-update-instructie.

Posjsonhelper

Hibernate biedt betere ondersteuning voor JSON-bewerking aan vanaf versie 7, inclusief de meeste functies en operators die in dit artikel worden genoemd. Toch zijn er geen plannen om zo’n ondersteuning toe te voegen in versie 6. Gelukkig biedt het Posjsonhelper-projectdergelijkeondersteuningaan voor Hibernate in versie 6. Alle voorbeelden hieronder zullen de Posjsonhelper-bibliotheek gebruiken.Bekijk dezelink om te leren hoe u een bibliotheek aan uw Java-project kunt koppelen. U zal ook moeten koppelen FunctionContributor.

Alle voorbeelden gebruiken een Java entity klasse die de tabel item weergeeft, waarvan de definitie hierboven werd genoemd:

Java

 

jsonb_set Function Wrapper

De functie jsonb_set is waarschijnlijk de meest nuttige functie bij het aanpassen van JSON gegevens nodig. Het stelt JSON objecten en specifieke array elementen beschikbaar op basis van de array index.

Bijvoorbeeld zorgt het onderstaande code ervoor dat de eigenschap "birthday" aan de binnenliggende eigenschap "child" wordt toegevoegd.

Java

 

Deze code zou de volgende SQL-instructie genereren:

SQL

 

Concatenatie Operator Wrapper “||”

De wrapper voor de concatenatie operator (||) concateneert twee JSONB waarden tot een nieuwe JSONB waarde.

Volgens de Postgres documentatie, gedraait het operator gedrag als volgt:

Concatenatie van twee array’s genereert een array dat alle elementen van elke invoer bevat. Concatenatie van twee objecten genereert een object dat de union bevat van hun sleutels, neemt de waarde van het tweede object over bij het optreden van dubbele sleutels. Alle andere gevallen worden behandeld door een niet-array invoer in een array met een enkel element om te zetten, en vervolgens wordt de behandeling als bij twee array’s doorgevoerd. Wordt niet recursief uitgevoerd: alleen de bovenste array of object structuur wordt samengevoegd.

Hier is een voorbeeld van hoe u deze wrapper in uw code kunt gebruiken:

Java

 

Code die een JSON object met de eigenschap child samenvoegt met het al opgeslagen JSON object in de database.

Deze code genereert zo’n SQL-query:

SQL

 

Verwijder het veld of array-element op basis van de index op het opgegeven pad “#-“

De Posjsonhelper heeft een wrapper voor de delete-bewerking (#-). Het verwijdert het veld of array element gebaseerd op de index op het gespecificeerde pad, waar pad elementen ofwel veld sleutels of array indexen kunnen zijn. De onderstaande code verwijdert bijvoorbeeld de eigenschap van het JSON-object op basis van het JSON-pad "child.pets".

Java

 

De gegenereerde SQL zou zijn:

SQL

 

Verschrap meerdere array-elementen op het opgegeven pad

Standaard heeft Postgres (tenminste in versie 16) geen ingebouwde functie waarmee array-elementen kunnen worden verwijderd op basis van hun waarde. Postgres heeft echter wel de ingebouwde operator -#, die we hierboven hebben genoemd, waarmee array-elementen kunnen worden verwijderd op basis van de index, maar niet op basis van hun waarde.

De Posjsonhelper kan hiervoor een functie genereren die moet worden toegevoegd aan de DDL-bewerking en moet worden uitgevoerd op je database.

SQL

 

Eén van de wrappers gebruikt deze functie om meerdere waarden uit de JSON-array te verwijderen. Deze code verwijdert een "mask" en "compass" elementen voor de "child.inventory" eigenschap.

Java

 

Hier is de SQL die wordt gegenereerd door de bovenstaande code:

SQL

 

Hibernate6JsonUpdateStatementBuilder: Hoe meerdere wijzigingsbewerkingen combineren met één updatestatement

Alle bovenstaande voorbeelden tonen de uitvoering van een enkele bewerking die JSON-gegevens wijzigt. Natuurlijk kunnen we in ons code update-declaraties hebben die samen met veel van de beschermers genoemd in dit artikel worden gebruikt. Het is echter belangrijk op de hoogte te zijn van hoe deze bewerkingen en functies zullen worden uitgevoerd, omdat dit het meest logisch is als het resultaat van de eerste JSON-bewerking de invoer is voor de volgende JSON-wijzigingsbewerkingen. Het uitvoeringsresultaat van deze bewerking zou de invoer zijn voor de volgende bewerking, enzovoort, tot de laatste JSON-wijzigingsbewerking.

Om dit beter te illustreren, kijk je naar de SQL-code.

SQL

 

Dit gaat ervan uit dat we vier keer jsonb_set function worden uitgevoerd en twee delete bewerkingen. De meest ingevoerde delete bewerking is de eerste JSON-wijzigingsbewerking, want de originele waarde uit een kolom die JSON-gegevens opslaat, wordt als parameter meegegeven.

Hoewel dit de correcte aanpak is, en de bestaande omhuller de mogelijkheid biedt om zo’n UPDATE-declaratie te maken, zou het misschien niet vanuit het perspectief van de code leesbaar zijn. gelukkig heeft Posjsonhelper een builder-component die het makkelijker maakt om zo’n complexe declaratie te bouwen.

Het type Hibernate6JsonUpdateStatementBuilder maakt het mogelijk om update-declaraties te bouwen met meerdere bewerkingen die JSON wijzigen en elkaar afhankelijk zijn.

Hieronder volgt een codevoorbeeld:

Java

 

De eerder genoemde SQL-declaratie werd door deze code gegenereerd.

Voor meer informatie over hoe de builder werkt, kijk dan eens naar de documentatie.

Conclusie

De Postgres database biedt veel mogelijkheden op het gebied van JSON-gegevensmodificaties. Dit maakt Postgres een goede keuze voor een documentenopslagoplossing. Dus, als onze oplossing geen hogere leesprestaties, betere schaalbaarheid of sharding vereist (hoewel alles dit met de Postgres database kan worden gerealiseerd, vooral met oplossingen aangeboden door cloudproviders zoals AWS), dan is het waard om aan te nemen dat uw JSON-documenten in de Postgres database opgeslagen kunnen worden — niet vergeleken met de ondersteuning van transacties met databases zoals Postgres.

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