sql >> Databasteknik >  >> RDS >> PostgreSQL

JSONB Array-uppdatering för specifikt element

PostgreSQL 11+

Om du redan är på PostgreSQL v. 11 (på grund av ny JSONB typ konverteringsstöd ) din bästa insats skulle förmodligen vara en anpassad funktion skriven i Perl eller Python.

Eftersom jag föredrar Python 3, här är ett funktionellt exempel:

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 sedan kan användas enligt följande:

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, villkoret är duplicerat, men bara för att begränsa antalet rader som ska röras i första hand.

För att faktiskt arbeta med en vanlig PostgreSQL 11-installation behöver du tilläggen plpython3u och jsonb_plpython3u :

CREATE EXTENSION plpython3u;
CREATE EXTENSION jsonb_plpython3u;

Python-logiken förklarade:

for e in path_to_array:
    tmp = tmp[e]

...får oss ner till den mängd poster vi behöver titta på.

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

...för varje objekt i arrayen kontrollerar vi om filterkriteriet är null (entry_filters is None =matcha valfri post) eller om posten "innehåller" det angivna exemplet inklusive nycklar och värden (entry_filters.items() <= item.items() ).

Om en post matchar, skriv över/lägg till innehåll med den medföljande ersättningen.

Jag hoppas att det går i den riktning du letar efter.

Om man tittar på de nuvarande funktionerna hos PostgreSQL relaterade till JSON-modifiering skulle det vara mycket komplext (om inte komplicerat) och introducera en hel del overhead för att göra samma sak med ren SQL.

PostgreSQL 9.6+

Om du inte har version 11 tillgänglig än, kommer följande funktion att göra detsamma på bekostnad av att hantera typkonverteringarna av sig själv men hålla den helt API-kompatibel, så du när du uppgraderar är det enda du behöver göra är att ersätta funktionen (ingen ändring av några satser som använder denna funktion krävs):

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. Spara bottillståndsdata i mySQL med .NET

  2. PostgreSQL sammansatt primärnyckel

  3. Hur man övervakar MySQL/MariaDB-databaser med Netdata på CentOS 7

  4. Initiering av en MySQL-databas distribuerad i en AWS EKS