Where in a JSON Postgres Array

Asked

Viewed 2,255 times

0

How can I select only the records that have the value "18" in this JSON?

'{"filtros":[
    {
        "tipo":"caracteristicas",
        "operador":"=",
        "valor":{"18":[12]}
    }
  ]}'

I tried to use the comparison with the @> but it didn’t work out because he didn’t return the record.

SELECT opcoes FROM pagina WHERE (opcoes->>'filtros')::jsonb @> '[18]'

2 answers

1

The tricky thing here is that filters is an array, so you can’t do the query directly, you have to scroll to each position of it.

For this, you must use the function jsonb_array_elements(jsonb). It will turn the results list into a "table" and you can give work with these results.

Imagine you have instead of 1 element inside filters, have 2 elements. Example:

'{"filtros":[
    { 
        "tipo":"caracteristicas", 
        "operador":"=",  
        "valor":{"18":[12]}
    },
    { 
        "tipo":"caracteristicas", 
        "operador":"=",  
        "valor":{"19":[12]}
    }
]}'

With (opcoes->>'filtros')::jsonb you will choose all elements of this array. With jsonb_array_elements you will turn it into tuples:

SELECT jsonb_array_elements((opcoes->>'filtros')::jsonb) FROM pagina limit 1;
                    jsonb_array_elements
---------------------------------------------------------------------
 {"tipo": "caracteristicas", "valor": {"18": [12]}, "operador": "="}
 {"tipo": "caracteristicas", "valor": {"19": [12]}, "operador": "="}
(2 rows)

But you still have to see if one of these guys has the "18" value. I imagine you wanted to look specifically at the field valor and not any field. For this you have to reference it in the query:

SELECT jsonb_array_elements((opcoes->>'filtros')::jsonb)->>'valor' FROM pagina limit 1;
   ?column?
--------------
{"18": [12]}
{"19": [12]}
(2 rows)

Now just see if the "value" has the '18' key using the operator ? (always remembering that you have to turn the result into a jsonb to allow the query).

SELECT (jsonb_array_elements((opcoes->>'filtros')::jsonb)->>'valor')::jsonb ? '18' FROM pagina limit 1;
   ?column?
--------------
t
f
(2 rows)

Since this result can return more than one row for each stored tuple, you can place it on a sub-allowance to make the filter, something like:

SELECT opcoes FROM pagina WHERE id in (
    SELECT DISTINCT id FROM pagina WHERE 
        (jsonb_array_elements((opcoes->>'filtros')::jsonb)->>'valor')::jsonb ? '18'
    );
  • Parts worked, but when I tried to use SELECT (jsonb_array_elements((options->'filters')::jsonb)->'value')::jsonb ? '18' FROM page limit 1; which for my case would be the most appropriate it returns error: ERROR: input syntax is invalid for type json DETAIL: End of expected input, found ",". CONTEXT: given JSON, line 1: 1,...

  • What prints the query: SELECT (jsonb_array_elements(((options->'filters')::jsonb)->>'value' ) FROM page limit 1;

  • Yes, this worked, but the problem was how much I tried to filter through the 18 record as you put in the penultimate SQL

  • I wanted to see the result of this query, because what it seems to be talking about is that the json contained in value is invalid.

  • I was able to solve it in a different way by doing so: SELECT options FROM page WHERE options::jsonb @> '{"filters":[{"value":{"18":[]}}]}'; but what you gave me helped me to get to the solution

0


I was able to solve it this way:

SELECT opcoes FROM pagina WHERE opcoes::jsonb @> '{"filtros":[{"valor":{"18":[]}}]}';
  • But this will only work when there is only one filter, no?

  • 1

    It worked with more filters. At the base I have several records and with the above select worked perfectly

Browser other questions tagged

You are not signed in. Login or sign up in order to post.