2

In a Postgres (9+) table there is a column of type jsonb with the following json:

{
   "dynamicFields":[
      {
         "name":"040",
         "subfields":[
            {
               "name":"a",
               "value":"abc"
            },
            {
               "name":"a",
               "value":"xyz"
            }
         ]
      }
   ]
}

I would like to write a query that return only the rows where the field name equals 040 and subfield a equals xyz.

This is as far as I got, so far:

select e.obj from my_table
cross join lateral jsonb_array_elements(my_column-> 'dynamicFields') as e(obj)
where e.obj ->> 'name' = '040' and e.obj ->> 'subfields' @> '{"name": "a", "value": "xyz"}'::jsonb

How should this query be to achieve this?

1
  • "9+" covers 13 different major versions 5 from them no longer being supported (and 3 of them do not even have jsonb) . Which version are you really using? Commented Jun 28, 2021 at 5:35

2 Answers 2

3

e.obj ->> 'subfields' has a text result. You'll want to use e.obj -> 'subfields' that returns the jsonb value where the @> operator works. Also the containment checks needs to have another array as the right hand side, so that it will test whether all values in the right array are contained in the left array - it doesn't work to pass the element object directly.

select e.obj from my_table
cross join lateral jsonb_array_elements(my_column-> 'dynamicFields') as e(obj)
where e.obj ->> 'name' = '040' and e.obj -> 'subfields' @> '[{"name": "a", "value": "xyz"}]'::jsonb
--                                        ^                 ^                             ^

(online demo)

Sign up to request clarification or add additional context in comments.

Comments

0

As you have an equality condition you can use the "contains" operator directly by providing a JSON value of what you want. There is no need to unnest the arrays.

select *
from my_table
where my_column -> 'dynamicFields' @> '[{"name": "040", "subfields": [{"name":"a", "value": "xyz"}]}]'

Starting with Postgres 12 an alternative is to a SQL/JSON path operator:

select *
from my_table
where my_column @? '$.dynamicFields[*] ? (@.name == "040").subfields[*] ? (@.name == "a" && @.value == "xyz")'

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.