sql >> Database >  >> RDS >> PostgreSQL

JSONB-array-update voor specifiek element

PostgreSQL 11+

Als je al bij PostgreSQL v. 11 bent (vanwege de nieuwe JSONB type conversie ondersteuning ) uw beste gok zou waarschijnlijk een aangepaste functie zijn die is geschreven in Perl of Python.

Aangezien ik de voorkeur geef aan Python 3, is hier een functioneel voorbeeld:

CREATE OR REPLACE FUNCTION jsonb_replace_in_array (val jsonb, path_to_array text[], replacement jsonb, entry_filters jsonb)
    RETURNS jsonb
    TRANSFORM FOR TYPE jsonb
    LANGUAGE plpython3u
AS $$
v_new = val
tmp = v_new
for e in path_to_array:
    tmp = tmp[e]

for item in tmp:
    if (entry_filters is None or entry_filters.items() <= item.items()):
        item.update(replacement)

return v_new
$$;

...die dan als volgt kan worden gebruikt:

UPDATE configuration
SET
  config = jsonb_replace_in_array(
    config,
    '{data}',
    '{"value":"changed"}'::jsonb,
    '{"oid":"11.5.15.1.4","instance":"1.1.4"}'::jsonb
  )
WHERE config->'data' @> '[{"oid":"11.5.15.1.4","instance":"1.1.4"}]';

Dus ja, de voorwaarde is gedupliceerd, maar alleen om het aantal rijen dat moet worden aangeraakt te beperken.

Om daadwerkelijk met een eenvoudige PostgreSQL 11-installatie te werken, hebt u extensies plpython3u nodig en jsonb_plpython3u :

CREATE EXTENSION plpython3u;
CREATE EXTENSION jsonb_plpython3u;

De Python-logica uitgelegd:

for e in path_to_array:
    tmp = tmp[e]

... brengt ons bij de reeks items die we moeten bekijken.

for item in tmp:
    if (entry_filters is None or entry_filters.items() <= item.items()):
        item.update(replacement)

...voor elk item in de array controleren we of het filtercriterium null is (entry_filters is None =overeenkomen met een item) of dat het item het opgegeven voorbeeld "bevat" inclusief sleutels en waarden (entry_filters.items() <= item.items() ).

Als en-invoer overeenkomt, overschrijf/voeg dan inhoud toe met de verstrekte vervanging.

Ik hoop dat dat in de richting gaat waar je naar op zoek bent.

Als we kijken naar de huidige mogelijkheden van PostgreSQL met betrekking tot JSON-modificatie, zou het erg complex zijn (zo niet ingewikkeld) en veel overhead introduceren om hetzelfde te doen met pure SQL.

PostgreSQL 9.6+

In het geval dat je nog geen versie 11 beschikbaar hebt, zal de volgende functie hetzelfde doen ten koste van het afhandelen van de typeconversies zelf, maar deze volledig API-compatibel houden, zodat je na een upgrade het enige bent dat je hoeft te doen is de functie vervangen (geen wijziging in instructies die deze functie gebruiken vereist):

CREATE OR REPLACE FUNCTION jsonb_replace_in_array (val jsonb, path_to_array text[], replacement jsonb, entry_filters jsonb)
    RETURNS jsonb
    LANGUAGE plpython3u
AS $$
import json

v_new = json.loads(val)
t_replace = json.loads(replacement)
t_filters = json.loads(entry_filters)
tmp = v_new
for e in path_to_array:
    tmp = tmp[e]

for item in tmp:
    if (entry_filters is None or t_filters.items() <= item.items()):
        item.update(t_replace)

return json.dumps(v_new)
$$;



  1. Hoe duplicaten te verwijderen, die worden gegenereerd met de functie array_agg postgres

  2. twee kolommen Draaien in Oracle SQL

  3. Groeperen op datumbereik met een interval van weken/maanden

  4. MySQL 8.0 - Client ondersteunt geen authenticatieprotocol dat door de server is aangevraagd; overweeg om MySQL-client te upgraden