Bearbeiten von JSON-Daten in Postgres und Hibernate 6

Dies ist ein weiterer Artikel in der Reihe, die sich mit der Unterstützung von Postgres-JSON-Funktionen in einem Projekt, das denHibernate-Framework mit Version 6 verwendet, beschäftigt. Der Artikel behandelt die Operationen der Modifizierung von JSON-Datensätzen. Wie im vorherigen Artikel erwähnt, hat Postgres möglicherweise keine umfassenden Operationen wie andere NoSQL-Datenbanken wie MongoDB für die JSON-Modifizierung (obwohl es mit den richtigen Funktionsbaukellen möglich ist, dasselbe Effekt zu erzielen). Es ist immer noch für die meisten Projekte geeignet, die JSON-Modifizierung benötigen. Plus, mit Transaktionsunterstützung (die ein NoSQL-Datenbank auf solch einem Niveau nicht bietet), ist es eine gute Idee, Postgres mit JSON-Daten zu verwenden. Natürlich bieten NoSQL-Datenbanken auch andere Vorteile, die für bestimmte Projekte besser geeignet sein könnten.

Es gibt im Allgemeinen viele Artikel über die Unterstützung von JSON durch Postgres. Der Artikel konzentriert sich auf die Integration dieser Unterstützung mit der Hibernate 6 Bibliothek.

Falls jemand an Interesse an der Abfrage von JSON-Daten oder dem Textsuchtengineering mit Postgres und Hibernate hat, ist er auf die unten stehenden Links aufmerksam zu halten:

Testdaten

Für das Artikel vermutet, dass unsere Datenbank eine Tabelle namens item hat, die eine Spalte mit JSON-Inhalt hat, wie im untenstehenden Beispiel gezeigt:

SQL

 

Wir könnten auch einige Testdaten haben:

SQL

 

Native SQL-Ausführung

Wie in anderen Java-Frameworks, kann man mit Hibernate native SQL-Abfragen ausführen — was gut dokumentiert ist und es gibt viele Beispiele auf dem Internet. Daher werden wir in diesem Artikel nicht auf die Ausführung von nativem SQL konzentrieren. Allerdings werden Beispiele gegeben darüber, welche Art von SQL die JPA-Operationen generieren. Da Hibernate eine JPA-Implementierung ist, ist es sinnvoll zu zeigen, wie die JPA-API JSON-Daten in der Postgres-Datenbank ändern kann.

Verändere JSON-Objekt-Eigenschaften und nicht das gesamte JSON-Objekt (Pfad)

Es ist einfach, den gesamten JSON-Payload für eine Spalte zu setzen und erfordert keine detaillierte Erklärung. Wir setzen einfach den Wert für die Eigenschaft in unserer Entity-Klasse, die eine Spalte mit JSON-Inhalt repräsentiert.

Es ist vergleichbar mit dem Setzen von einzelnen oder mehreren Eigenschaften für JSON für eine Datensatz in der Datenbank. Wir lesen einfach die Tabellenspalte, deserialisieren den JSON-Wert zu einem POJO, das ein JSON-Objekt repräsentiert, setzen Werte für bestimmte Eigenschaften und aktualisieren die Datenbankdatensätze mit dem gesamten Payload. Allerdings könnte diese Methode nicht praktisch sein, wenn wir JSON-Eigenschaften für mehrere Datensätze in der Datenbank ändern möchten.

Stellen wir uns vor, wir müssen eine Stapelaktualisierung von bestimmten JSON-Eigenschaften durchführen. Das Abrufen der Datenbank und die Aktualisierung jedes Datensatzes könnte keine wirklich effiziente Methode sein.

Es wäre deutlich besser, eine solche Aktualisierung mit einer einzigen update-Anweisung durchzuführen, in der wir Werte für bestimmte JSON-Eigenschaften setzen. Glücklicherweise bietet Postgres Funktionen an, die den Inhalt von JSON verändern und in einer SQL-Aktualisierungsanweisung verwendet werden können.

Posjsonhelper

Hibernate bietet in Version 7 bessere Unterstützung für die JSON-Veränderung, einschließlich der meisten der in diesem Artikel erwähnten Funktionen und Operatoren. Trotzdem gibt es keine Pläne, solche Unterstützung in Version 6 hinzuzufügen. Glücklicherweise ergänzt das Posjsonhelper-Projekt diese Unterstützung für Hibernate in Version 6. Alle Beispiele, die unten gezeigt werden, werden die Posjsonhelper-Bibliothek verwenden.Schauen Sie auf diesen Link, um zu erfahren, wie Sie eine Bibliothek zu Ihrem Java-Projekt hinzufügen. Sie müssen auch den FunctionContributor attachen..

Alle Beispiele verwenden eine Java Entität Klasse, die die item Tabelle repräsentiert, deren Definition oben erwähnt wurde:

Java

 

jsonb_set-Funktion Wrapper

Die jsonb_set Funktion ist wahrscheinlich die am meisten hilfreiche Funktion, wenn es darum geht, JSON-Daten zu verändern. Sie erlaubt es, bestimmte Eigenschaften für JSON-Objekte und bestimmte Arrayelemente basierend auf dem Array-Index zu setzen.

Zum Beispiel fügt das folgende Codebeispiel der inneren Eigenschaft "child" die Eigenschaft "birthday" hinzu.

Java

 

Dieser Code generiert einen SQL-Befehl wie folgt:

SQL

 

Verbindungsoperator Wrapper „||“

Der Wrapper für den Verbindungsoperator (||) verbindet zwei JSONB-Werte zu einem neuen JSONB-Wert.

Nach den Postgres Dokumentationen verhält sich der Operator wie folgt:

Verbinden von zwei Arrays erzeugt ein Array, das alle Elemente jedes Eingabearrays enthält. Verbinden von zwei Objekten erzeugt ein Objekt, das die Vereinigung ihrer Schlüssel enthält, wobei der zweite Wert bei duplizierten Schlüsseln verwendet wird. Alle anderen Fälle werden behandelt, indem ein nicht-arrayspezifischer Eingabewert in ein einzelnelementiges Array umgewandelt wird, und dann wie bei zwei Arrays fortgefahren wird. Operiert nicht rekursiv: Es wird nur die oberste Ebene des Array- oder Objekt-Struktur verknüpft.

Hier ist ein Beispiel, wie Sie diesen Wrapper in Ihrem Code verwenden können:

Java

 

Code, der ein JSON-Objekt mit der Eigenschaft child mit dem bereits in der Datenbank gespeicherten JSON-Objekt zusammenführt.

Dieser Code generiert einen SQL-Aufruf wie folgt:

SQL

 

Felder oder Arrayelemente basierend auf der Indexposition an der angegebenen Pfad entfernen „#-„

Der Posjsonhelper verfügt über einen Wrapper für die Löschoperation (#-). Er entfernt das Feld oder das Arrayelement basierend auf dem Index an der angegebenen Stelle, wobei die Stellenangaben entweder Feld Schlüssel oder Array-Indizes sein können. Zum Beispiel wird der untenstehende Code das JSON-Objekt auf Basis des JSON-Pfads "child.pets" entfernen.

Java

 

Die generierte SQL-Anweisung würde lauten:

SQL

 

Mehrere Arrayelemente an der angegebenen Pfad entfernen

Standardmäßig besitzt Postgres (mindestens in Version 16) keine integrierte Funktion, die Arrayelemente aufgrund ihres Werts löschen erlaubt. Allerdings besitzt es die integrierte Operation -#, die wir oben erwähnt haben und die hilft, Arrayelemente auf der Basis ihres Index zu löschen, nicht jedoch aufgrund ihres Werts.

Zu diesem Zweck kann der Posjsonhelper eine Funktion generieren, die zu der Datenbank hinzugefügt und bei der DDL-Operation durchgeführt werden muss.

SQL

 

Einer der Wrapper wird diese Funktion verwenden, um die Löschung mehrerer Werte aus dem JSON-Array zu ermöglichen. Dieser Code entfernt ein Element mit dem Schlüssel "mask" und "compass" für die Eigenschaft "child.inventory".

Java

 

Hier ist die von obenstehendem Code generierte SQL:

SQL

 

Hibernate6JsonUpdateStatementBuilder: Wie kann man mehrere Änderungsoperationen mit einer Update-Anweisung kombinieren?

Alle obigen Beispiele zeigten die Ausführung einer einzigen Operation, die JSON-Daten verändert. Natürlich können wir in unserem Code Update-Anweisungen haben, die mehrere der in diesem Artikel erwähnten Schrapper zusammen verwenden. Jedoch ist es wichtig zu wissen, wie diese Operationen und Funktionen ausgeführt werden, da es sinnvoll ist, wenn das Ergebnis der ersten JSON-Operation die Eingabe für die folgenden JSON-Veränderungsoperationen ist. Das Ergebnis dieser Operation würde die Eingabe für die nächste Operation sein und so fort, bis zur letzten JSON-Veränderungsoperation.

Um das zu verdeutlichen, schauen Sie auf den SQL-Code.

SQL

 

Dies setzt voraus, dass wir vier jsonb_set function-Ausführungen und zwei delete-Operationen haben. Die tiefgestaffelte delete-Operation ist eine erste JSON-Veränderungsoperation, weil der ursprüngliche Wert einer Spalte, die JSON-Daten speichert, als Parameter übergeben wird.

Obwohl dies die richtige Methode ist und der bestehende Schrapper die Erstellung solcher UPDATE-Anweisungen zulässt, mag dies aus Code-Perspektive nicht lesbar sein. Glücklicherweise bietet Posjsonhelper einBuilder-Komponente, die die Erstellung solcher komplexen Anweisungen einfach macht.

Der Typ Hibernate6JsonUpdateStatementBuilder ermöglicht die Erstellung von Update-Anweisungen mit mehreren Operationen, die JSON verändern und sich gegenseitig aufrufen.

Unten ist ein Codebeispiel:

Java

 

Der zuvor erwähnte SQL-Anweisung wurde durch diesen Code generiert.

Um mehr über die Arbeitsweise des Erstellers zu erfahren, bitte die Dokumentation anschauen.

Schlussfolgerung

Postgres-Datenbank bietet eine Vielzahl von Möglichkeiten für Operationen zur Bearbeitung von JSON-Daten. Dies veranlasst uns, Postgres als eine gute Wahl für die Dokumentenspeicherung zu betrachten. Also, wenn unsere Lösung keine höheren Lesepufferleistungen, bessere Skalierbarkeit oder Sharding-Funktionen (obwohl all dies mit der Postgres-Datenbank erreichbar ist, insbesondere mit Lösungen, die von Cloud-Anbietern wie AWS bereitgestellt werden) erfordert, dann ist es lohnenswert, darauf zu achten, Ihre JSON-Dokumente in einer Postgres-Datenbank zu speichern – ganz zu schweigen von der Transaktionsunterstützung durch Datenbanken wie Postgres.

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