0

I am looking to you for help in adding a property to a json object nested in 2 arrays.

Table Example :

CREATE TABLE events (
    seq_id BIGINT PRIMARY KEY,
    data JSONB NOT NULL,
    evt_type TEXT NOT NULL
);

example of my JSONB data column in my table:

{
   "Id":"1",
   "Calendar":{
      "Entries":[
         {
            "Id": 1,
            "SubEntries":[
               {
                  "ExtId":{
                     "Id":"10",
                     "System": "SampleSys"
                  },
                  "Country":"FR",
                  "Details":[
                     {
                        "ItemId":"1",
                        "Quantity":10,
                     },
                     {
                        "ItemId":"2",
                        "Quantity":3,
                     }
                  ],
                  "RequestId":"222",
                  "TypeId":1,
               }
            ],
            "OrderResult":null
         }
      ],
      "OtherThingsArray":[
         
      ]
   }
}

So I need to add new properties into a SubEntries object based on the Id value of the ExtId object (The where clause)

How can I do that please ?

Thanks a lot

1
  • 1
    Please add your JSON expected Commented Sep 29, 2021 at 20:36

1 Answer 1

1

You can use jsonb_set() for this, which takes jsonpath assignments as a text[] (array of text values) as

SELECT jsonb_set(
  • input_jsonb,

the starting jsonb document

  • path_array '{i,j,k[, ...]}'::text[],

the path array, where the series {i, j, k} progresses at each level with either the (string) key or (integer) index (starting at zero)denoting the new key (or index) to populate

  • new_jsonb_value,

if adding a key-value pair, you can use something like to_jsonb('new_value_string'::text) here to force things to format correctly

  • create_if_not_exists_boolean

if adding new keys/indexes, give this as true so they'll be appended; otherwise you'll be limited to overwriting existing keys

) 

Example

json

{
  "array1": [
    {
      "id": 1,
      "detail": "test"
    }
  ]
}

SQL

SELECT 
    jsonb_set('{"array1": [{"id": 1, "detail": "test"}]}'::jsonb,
    '{array1,0,update}'::TEXT[],
    to_jsonb('new'::text),
    true
) 

Output

{
  "array1": [
    {
      "id": 1,
      "upd": "new",
      "detail": "test"
    }
  ]
}

Note that you can only add 1 nominal level of depth at a time (i.e. either a new key or a new index entry), but you can circumvent this by providing the full depth in the assignment value, or by using jsonb_set() iteratively:

select
    jsonb_set( 
jsonb_set('{"array1": [{"id": 1, "detail": "test"}]}'::jsonb, '{array1,0,upd}'::TEXT[], '[{"new": "val"}]'::jsonb, true), 
    '{array1,0,upd,0,check}'::TEXT[],
    '"test_val"',
    true)

would be required to produce

{
  "array1": [
    {
      "id": 1,
      "upd": [
        {
          "new": "val",
          "check": "test_val"
        }
      ],
      "detail": "test"
    }
  ]
}

If you need other, more complex logic to evaluate which values need to be added to which objects, you can try:

  • dynamically creating a set of jsonb_set() statements for execution
  • using the outputs from queries of jsonb_each() and jsonb_array_elements() to evaluate the row logic down at the SubEntities level, and then using jsonb_object_agg() and jsonb_agg() as appropriate to build the document back up to the root level from the resultant object-arrays and key-value collections
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.