How do I modify fields inside the new PostgreSQL JSON datatype?

前端 未结 21 1967
孤独总比滥情好
孤独总比滥情好 2020-11-22 15:37

With postgresql 9.3 I can SELECT specific fields of a JSON data type, but how do you modify them using UPDATE? I can\'t find any examples of this in the postgresql documenta

相关标签:
21条回答
  • 2020-11-22 16:34

    Even though the following will not satisfy this request (the function json_object_agg is not available in PostgreSQL 9.3), the following can be useful for anyone looking for a || operator for PostgreSQL 9.4, as implemented in the upcoming PostgreSQL 9.5:

    CREATE OR REPLACE FUNCTION jsonb_merge(left JSONB, right JSONB)
    RETURNS JSONB
    AS $$
    SELECT
      CASE WHEN jsonb_typeof($1) = 'object' AND jsonb_typeof($2) = 'object' THEN
           (SELECT json_object_agg(COALESCE(o.key, n.key), CASE WHEN n.key IS NOT NULL THEN n.value ELSE o.value END)::jsonb
            FROM jsonb_each($1) o
            FULL JOIN jsonb_each($2) n ON (n.key = o.key))
       ELSE 
         (CASE WHEN jsonb_typeof($1) = 'array' THEN LEFT($1::text, -1) ELSE '['||$1::text END ||', '||
          CASE WHEN jsonb_typeof($2) = 'array' THEN RIGHT($2::text, -1) ELSE $2::text||']' END)::jsonb
       END     
    $$ LANGUAGE sql IMMUTABLE STRICT;
    GRANT EXECUTE ON FUNCTION jsonb_merge(jsonb, jsonb) TO public;
    CREATE OPERATOR || ( LEFTARG = jsonb, RIGHTARG = jsonb, PROCEDURE = jsonb_merge );
    
    0 讨论(0)
  • 2020-11-22 16:34

    I found previous answers are suitable experienced PostgreSQL users, hence my answer:

    Assume you have the a table-column of type JSONB with the following value:

    {
        "key0": {
            "key01": "2018-05-06T12:36:11.916761+00:00",
            "key02": "DEFAULT_WEB_CONFIGURATION",
    
        "key1": {
            "key11": "Data System",
            "key12": "<p>Health,<p>my address<p>USA",
            "key13": "*Please refer to main screen labeling"
        }
    }
    

    let's assume we want to set a new value in the row:

    "key13": "*Please refer to main screen labeling"
    

    and instead place the value:

    "key13": "See main screen labeling"
    

    we use the json_set() function to assign a new value to the key13

    the parameters to jsonb_set()

    jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])
    

    in "target" - I will place the jsonb column-name (this is the table column that is being modified)

    "path"- is the "json keys path" leading-to (and including) the key that we are going to overwrite

    "new_value" - this is the new value we assign

    in our case we want to update the value of key13 which resides under key1 ( key1 -> key13 ) :

    hence the path syntax is : '{key1,key13}' (The path was the most tricky part to crack - because the tutorials are terrible)

    jsonb_set(jsonb_column,'{key1,key13}','"See main screen labeling"')
    
    0 讨论(0)
  • 2020-11-22 16:35

    I wrote small function for myself that works recursively in Postgres 9.4. Here is the function (I hope it works well for you):

    CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
    RETURNS JSONB AS $$
    DECLARE
        result JSONB;
        v RECORD;
    BEGIN
        IF jsonb_typeof(val2) = 'null'
        THEN 
            RETURN val1;
        END IF;
    
        result = val1;
    
        FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP
    
            IF jsonb_typeof(val2->v.key) = 'object'
                THEN
                    result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
                ELSE
                    result = result || jsonb_build_object(v.key, v.value);
            END IF;
        END LOOP;
    
        RETURN result;
    END;
    $$ LANGUAGE plpgsql;
    

    Here is sample use:

    select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
                                jsonb_update                             
    ---------------------------------------------------------------------
     {"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
    (1 row)
    

    As you can see it analyze deep down and update/add values where needed.

    0 讨论(0)
  • 2020-11-22 16:37

    If you are making this query with a programming language client, eg from python pycopg2, or Node Postgres, Make sure you parse the new data to JSON first.

    It might easily look like a python dictionary is the Same as a JSON object but it does not first do json.dumps on the dictionary.

    A simple python snippet:

    def change_destination(self,parcel_id,destlatlng): query="UPDATE parcels SET destlatlng = '{}' WHERE parcel_id ={};".format(json.dumps(destlatlng), parcel_id) self.cursor.execute(query2) self.connection.commit()

    0 讨论(0)
  • 2020-11-22 16:38

    With 9.5 use jsonb_set-

    UPDATE objects
    SET body = jsonb_set(body, '{name}', '"Mary"', true)
    WHERE id = 1; 
    

    where body is a jsonb column type.

    0 讨论(0)
  • 2020-11-22 16:38
    UPDATE test
    SET data = data::jsonb - 'a' || '{"a":5}'::jsonb
    WHERE data->>'b' = '2'
    

    This seems to be working on PostgreSQL 9.5

    0 讨论(0)
提交回复
热议问题