sql >> Database teknologi >  >> RDS >> PostgreSQL

JSONB Array-opdatering til specifikt element

PostgreSQL 11+

Hvis du allerede er på PostgreSQL v. 11 (på grund af ny JSONB type konverteringsstøtte ) dit bedste bud ville sandsynligvis være en brugerdefineret funktion skrevet i Perl eller Python.

Da jeg foretrækker Python 3, er her et funktionelt eksempel:

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
$$;

...som så kan bruges som følger:

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"}]';

Så ja, betingelsen er duplikeret, men kun for at begrænse antallet af rækker, der skal berøres i første omgang.

For rent faktisk at arbejde ved en almindelig PostgreSQL 11-installation skal du bruge udvidelser plpython3u og jsonb_plpython3u :

CREATE EXTENSION plpython3u;
CREATE EXTENSION jsonb_plpython3u;

Python-logikken forklarede:

for e in path_to_array:
    tmp = tmp[e]

...får os ned til den række af poster, vi skal se på.

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

...for hvert element i arrayet kontrollerer vi, om filterkriteriet er null (entry_filters is None =matcher en hvilken som helst post), eller om indgangen "indeholder" det angivne eksempel inklusive nøgler og værdier (entry_filters.items() <= item.items() ).

Hvis en post matcher, så overskriv/tilføj indhold med den medfølgende erstatning.

Jeg håber, det går i den retning, du leder efter.

Ser man på de nuværende muligheder for PostgreSQL relateret til JSON-modifikation, ville det være meget komplekst (hvis ikke kompliceret) og introducere en masse overhead for at gøre det samme med ren SQL.

PostgreSQL 9.6+

Hvis du ikke har version 11 tilgængelig endnu, vil følgende funktion gøre det samme på bekostning af at håndtere typekonverteringerne af sig selv, men holde den fuldstændig API-kompatibel, så du, når du først har opgraderet, er det eneste du skal gøre er erstatte funktionen (ingen ændring af nogen udsagn, der bruger denne funktion påkrævet):

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. Sådan kopieres data fra en tabel til en anden i SQL

  2. Skift fra SQLite til MySQL med Flask SQLAlchemy

  3. MySQL fejlkode:1175 under OPDATERING i MySQL Workbench

  4. C# opretter forbindelse til en postgres-database