Where in an Array JSON Postgres

0

How can I do to 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 @> but it did not work, because it does not return the registry.

SELECT opcoes FROM pagina WHERE (opcoes->>'filtros')::jsonb @> '[18]'
    
asked by anonymous 04.12.2017 / 13:53

2 answers

0

I was able to resolve it as follows:

SELECT opcoes FROM pagina WHERE opcoes::jsonb @> '{"filtros":[{"valor":{"18":[]}}]}';
    
07.12.2017 / 14:53
1

The trick here is that filters are an array, so you can not do the query directly, you have to go through each position of it.

For this, you should use the jsonb_array_elements(jsonb) function. It will transform the list of results into a "table" and you can give work with those results.

Imagine that 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 transform 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 value "18". I imagine you wanted to look specifically at the valor field 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 key '18' using the operator ? (always remembering that you have to transform 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)

As this result can return more than one row for each stored tuple, you can put it in a subquery to do 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'
    );
    
07.12.2017 / 02:24