Modificare i dati JSON in Postgres e Hibernate 6

Questo è un altro articolo della serie relativa al supporto delle funzioni JSON di Postgres in un progetto che utilizza il framework Hibernate versione 6. Il soggetto dell’articolo sono le operazioni di modifica sui record JSON. Come negli articoli precedenti, vale la pena menzionare che Postgres potrebbe non avere operazioni così complete come altri database NoSQL come MongoDB per la modifica di JSON (sebbene, con le costruzioni di funzione appropriate, sia possibile ottenere lo stesso effetto). Ancora una volta, si adatta a molti progetti che richiedono la modifica di JSON. Inoltre, supportando le transazioni (funzionalità non presente in un database NoSQL a questo livello), è una scelta piuttosto buona utilizzare Postgres con dati JSON. Certamente, i database NoSQL hanno altri benefici che potrebbero essere più adatti a determinati progetti.

Si trovano generalmente molti articoli sull’ supporto diJSON di Postgres. Questo articolo si concentra sull’integrazione di questo supporto con la libreria Hibernate 6.

In caso qualcuno sia interessato alla ricerca di dati JSON o alla ricerca testuale utilizzando Postgres e Hibernate, si prega di consultare i link sottostanti:

Dati di test

Pensando al nostro articolo, supponiamo che la nostra base dati abbia una tabella chiamata item, che ha una colonna con contenuto JSON, come nell’esempio seguente:

SQL

 

Potremmo anche avere alcuni dati di testo:

SQL

 

Esecuzione SQL Naturale

Come in altri framework Java, con Hibernate è possibile eseguire query SQL native — che sono ben documentate e ci sono molti esempi sulla rete. Per questo motivo, questo articolo non si concentrerà sull’esecuzione delle operazioni di SQL native. tuttavia, ci saranno esempi di ciò che tipo di SQL le operazioni JPA generano. Poiché Hibernate è una implementazione di JPA, ha senso mostrare come l’API JPA possa modificare i dati JSON nel database Postgres.

Modifica le proprietà dell’oggetto JSON e non l’intero oggetto JSON (Percorso)

Impostare l’intero payload JSON per una colonna è facile e non richiede spiegazioni dettagliate. Semplicemente impostiamo il valore della proprietà nella nostra classe Entity, che rappresenta una colonna con contenuto JSON.

È simile ad impostare singole o più proprietà JSON per una riga di database. Leggiamo semplicemente la riga della tabella, deserializziamo il valore JSON in un POJO che rappresenta un oggetto JSON, impostiamo i valori per proprietà specifiche e aggiorniamo i record del database con l’intero payload. Tuttavia, questo approcio potrebbe non essere pratico quando vogliamo modificare le proprietà JSON per molte righe del database.

Supponiamo di dover eseguire aggiornamenti di batch su proprietà JSON specifiche. Recuperare il database e aggiornare ogni record potrebbe non essere un metodo efficiente.

Sarebbe molto meglio eseguire un aggiornamento come questo con una sola istruzione update in cui impostiamo i valori per proprietà JSON specifiche. Fortunatamente, Postgres offre funzioni in grado di modificare il contenuto JSON e possono essere utilizzate nell’istruzione SQL di aggiornamento.

Posjsonhelper

Hibernate offre un migliore supporto per la modifica di JSON nella versione 7, inclusi la maggior parte delle funzioni e operatori menzionati in questo articolo. Comunque, non ci sono piani per aggiungere questo supporto nella versione 6. Fortunatamente, il progetto Posjsonhelper aggiunge questo supportoper Hibernate nella versione 6. Tutti gli esempi riportati di seguito useranno la libreria Posjsonhelper. Consultare questo link per scoprire come allegare una libreria al proprio progetto Java. Dovrai anche allegare FunctionContributor.

Tutti gli esempi utilizzano la classe entità Java che rappresenta la tabella item, la cui definizione è stata menzionata in precedenza:

Java

 

jsonb_set Function Wrapper

La funzione jsonb_set è probabilmente la funzione più utile quando è necessario modificare i dati JSON. Consente di impostare proprietà specifiche per gli oggetti JSON e specifici elementi di array, in base all’indice dell’array.

Ad esempio, il codice seguente aggiunge la proprietà "compleanno" alla proprietà interna "bambino".

Java

 

Questo codice genererebbe un’istruzione SQL di questo tipo:

SQL

 

Concatenation Operator Wrapper “||”

Il wrapper per l’operatore concatenation (||) concatena due valori JSONB in un nuovo valore JSONB.

Sulla base della documentazione di Postgres, il comportamento dell’operatore è il seguente:

Concatenare due array genera un array contenente tutti gli elementi di ciascun input. La concatenazione di due oggetti genera un oggetto contenente l’unione delle loro chiavi, prendendo il valore del secondo oggetto quando ci sono chiavi duplicate. Tutti gli altri casi vengono trattati convertendo un input non array in un array a singolo elemento e procedendo poi come per due array. Non opera in modo ricorsivo: viene unito solo l’array di primo livello o la struttura dell’oggetto.

Ecco un esempio di come utilizzare questo wrapper nel codice:

Java

 

Codice che unisce un oggetto JSON con la proprietà child con l’oggetto JSON già memorizzato nel database.

Questo codice genera una query SQL di questo tipo:

SQL

 

Elimina il campo o l’elemento dell’array in base all’indice specificato nel percorso “#-“

Il Posjsonhelper include unwrapper per l’operazione di eliminazione (#-). Elimina il campo o l’elemento dell’array in base all’indice specificato nel percorso, in cui i membri del percorso possono essere chiavi di campi o indici di array. Per esempio, il codice seguente rimuove dalla proprietà dell’oggetto JSON in base al percorso JSON "child.pets".

Java

 

Il SQL generato sarebbe:

SQL

 

Elimina multipli elementi dell’array presso il percorso specificato

Per default, Postgres (almeno nella versione 16) non ha una funzione integrata che consente la rimozione di elementi dell’array in base al loro valore. tuttavia, dispone dell’operatore integrato -#, che abbiamo menzionato prima, che aiuta a eliminare elementi dell’array in base all’indice ma non al loro valore.

A questo scopo, il Posjsonhelper può generare una funzione che deve essere aggiunta all’operazione DDL e eseguita sul tuo database.

SQL

 

Uno degli wrapper userà questa funzione per consentire l’eliminazione di molti valori dall’array JSON. questo codice rimuove gli elementi "mask" e "compass" per la proprietà "child.inventory".

Java

 

Ecco il SQL generato dal codice precedente:

SQL

 

Hibernate6JsonUpdateStatementBuilder: Come combinare multipli operazioni di modifica in una sola istruzione di aggiornamento.

Tutti gli esempi precedenti hanno dimostrato l’esecuzione di una singola operazione che modifica i dati JSON. Naturalmente, possiamo avere istruzioni di aggiornamento nel nostro codice che usino molti wrapper menzionati in questo articolo insieme. Tuttavia, è fondamentale essere consapevoli di come queste operazioni e funzioni verranno eseguite perché è più logico quando il risultato dell’ prima operazione JSON è l’input per le operazioni di modifica JSON successive. L’output di quell’operazione sarebbe l’input per l’operazione successiva, e così via, fino all’ultima operazione di modifica JSON.

Per illustrare meglio questo concetto, controllate il codice SQL.

SQL

 

Questo presuppone che abbiamo quattro esecuzioni della funzione jsonb_set e due operazioni delete. L’operazione delete più ricca di nodi è una prima operazione di modifica JSON perché il valore originale di una colonna che memorizza i dati JSON viene passato come parametro.

Anche se questo è l’approcio corretto e i wrapper esistenti consentono la creazione di un tale UPDATE statement, potrebbe non essere leggibile da un punto di vista del codice. Fortunatamente, Posjsonhelper ha un componente builder che rende semplice la costruzione di un tale statamento complesso.

Il tipo Hibernate6JsonUpdateStatementBuilder consente la costruzione di istruzioni di aggiornamento con operazioni multiple che modificano il JSON e si basano l’una sull’altra.

Ecco un esempio di codice:

Java

 

Il comando SQL menzionato precedentemente è stato generato da questo codice.

Per sapere di più su come funziona il costruttore, consultare la documentazione.

Conclusione

La base di dati Postgres offre un vasto range di possibilità nell’operazione di modifica di dati JSON. Ciò ci porta a considerare Postgres come una buona scelta per il salvataggio di documenti. Quindi, se la nostra soluzione non richiede alte prestazioni in lettura, un migliore scalabilità o sharding (anche se tutte queste cose possono essere raggiunte con la base di dati Postgres, specialmente con soluzioni fornite da provider cloud come AWS), allora è degno di considerazione il salvataggio dei vostri documenti JSON in una base di dati Postgres — non menzionando il supporto per le transazioni offerto da basi di dati come Postgres.

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