variable substitution querying postgres jsonb object - postgresql

Hi I am querying a JSONb object where the search key depends on the value of another key/value pair. Consider the following example:
select
'{"a":"b","b":2}'::jsonb->'a',--b,
('{"a":"b","b":2}'::jsonb->'a')::text,--"b"
'{"a":"b","b":2}'::jsonb->('{"a":"b","b":2}'::jsonb->'a')::text--null, desired output is 2
Somehow I need to dereference the "b" to a json search path like 'b'
Any suggestions will be greatly appreciated

You should tu use ->> operator instead ->. There was unwanted double quoting:
select
'{"a":"b","b":2}'::jsonb->'a',--b,
('{"a":"b","b":2}'::jsonb->>'a')::text,--"b"
'{"a":"b","b":2}'::jsonb->('{"a":"b","b":2}'::jsonb->>'a')::text;

Related

Postgres JSONB values are all strings

Somehow populating a database with a JSONB column ended up with every value in the column being a JSONB string instead of an object.
=> select specifications from checklist_item;
specifications
---------------------
"{}"
"{}"
"{\"x\": 2, \"y\": \"z\"}"
Is it possible to update, in a single statement, each of these values to JSONB objects as opposed to strings?
I tried to_jsonb(specifications) but that did not parse as expected. I've gone over documentation but all the examples seem to show ways to manipulate data that is already a jsonb array or a jsonb object but not a plain string.
I can write a script and do the parsing in Python, but there certainly must be a nice way to do with in a single update command with a json function that I simply cannot find at the moment. Is there such a json function or operator that will "parse" my bad data?
to_jsonb(specifications) does to_jsonb(specifications::text), which just gets the JSON text with the string literal as text. What you need is to get the value of the JSON string literal, then cast that to jsonb:
UPDATE checklist_item
SET specifications = (specifications #>> '{}')::jsonb
-- or … = to_jsonb(specifications #>> '{}')
WHERE jsonb_typeof(specifications) = 'string';

Can't parse JSONB scalar as array in Postgres

I'm on PostgreSQL 13.2. I have a table with a JSONB column, and it stores JSONs that are a list of objects:
"[{\"MyKey\":\"ValueXYZ\",\"Counter\":0}, {\"MyKey\":\"ValueABC\",\"Counter\":3}]"
When I test this column for a type with jsonb_typeof() like so:
select jsonb_typeof(i.my_column) as col_type
from items i
where i.id = 342
I get string. Which tells me this value is a scalar, and I'm wondering if maybe it wasn't inserted properly.
The error that is bothering me is I am trying to parse the column with something like this:
select jsonb_array_elements(i.my_column)
from items i
and I see the error:
SQL Error [22023]: ERROR: cannot extract elements from a scalar
What is going on? Is there a way to fix this?
Yes, it got inserted wrong. It contains a scalar, which happens to be holding the string representation of a JSON array. The string representation of a JSON array is a different thing than an actual JSON array.
You can extract the string value from the scalar, then cast that string into a jsonb. #>>'{}' will extract the string out of a scalar.
select jsonb_array_elements((i.my_column#>>'{}')::jsonb)
from items i ;
Although you should fundamentally fix the problem, by re-storing the values correctly.
update items set my_column = (my_column#>>'{}')::jsonb where jsonb_typeof(my_column)='string';
But of course you should fix whatever is doing the incorrect insertions first.
Looks like a quoting issue. Consider:
test=> SELECT jsonb_typeof(jsonb '[{"MyKey":"ValueXYZ","Counter":0}, {"MyKey":"ValueABC","Counter":3}]') AS col_type;
col_type
----------
array
(1 row)

How can I use key/value dashboard variables in Grafana + InfluxDB?

I’m trying to suss out how to format my key/value pair dashboard variable. I’ve got a variable whose definitions are:
sensor_list = 4431,8298,11041,13781
sensor_kv = 4431 : Storage,8298 : Stairs,11041 : Closet,13781 : Attic
However, I can't seem to use it effectively for queries and dashboard formatting with InfluxDB. For example, I've got a panel whose query is this:
SELECT last("battery_ok") FROM "autogen"."Acurite-Tower" WHERE ("id" =~ /^$sensor_list$/) AND $timeFilter GROUP BY time($__interval) fill(null)
That works, but if I replace it with the KV, I can't get the value:
SELECT last("battery_ok") FROM "autogen"."Acurite-Tower" WHERE ("id" =~ /^$sensor_kv$/) AND $timeFilter GROUP BY time($__interval) fill(null)
^ that comes back with no data.
I'm also at a loss as to how to access the value of the KV pair in, say, the template values for a repeating panel. ${sensor_kv:text} returns the word "All" but ${sensor_kv:value} actually causes a straight up error: "Error: Variable format value not found"
My goal here is twofold:
To use the key side of the kv map as the ID to query from in the DB
To use the value side as the label of the stat panel and also as the alias of the measurement if I'm querying in a graph
I’ve read the formatting docs and all they mention are lists; there are no key/value examples on there, and certainly none that do this. It’s clearly a new-ish feature (here is the GH issue where its implementation is merged) so I’m hoping there’s just a doc miss somewhere.
In PR that you linked there is a tiny comment that key/value pair has to contain spaces.
So when you're defining a pairs in Values separated by comma it should be like
key1 : value1, key2 : value2
These will not work
key1:value1, key2:value2
key1 :value1, key2 :value2
key1: value1, key2: value2
Let's say that name of the custom variable is var1
Then you can access the key by ${var1} ,$var1, ${var1:text} or [[var1:text]]
(some datasources will be satisfied with $var1 - some will understand only ${var1:text})
And you can access the value by ${var1:value} [[var1:value]]
Tested in Grafana 8.4.7
I realise this might not be all the information you're after, but hope it will be useful. I came across this question when trying to implement something similar myself (also using InfluxDB), and I have managed to access both keys and values in a query
My query looks like this:
SELECT
"Foo.${VariableName:text}.Bar.${VariableName:value}"
FROM "db"
WHERE (filters, filters) AND $timeFilter GROUP BY "bas"
So as you see, my use case was a bit different from what you're trying to achieve, but it demonstrates that it's basically possible to access both the key and the value in a query.
Key/values are working with some timeseries DB where it makes sense, e.g. MySQL https://grafana.com/docs/grafana/latest/datasources/mysql/:
Another option is a query that can create a key/value variable. The query should return two columns that are named __text and __value. The __text column value should be unique (if it is not unique then the first value is used). The options in the dropdown will have a text and value that allows you to have a friendly name as text and an id as the value.
But that's not a case for InfluxDB: https://grafana.com/docs/grafana/latest/datasources/influxdb/ InfluxDB can't return key=>value result - it returns only timeseries (that's not a key=>value) or only values or only keys.
Workarounds:
1.) Use supported DB (MySQL, PostgreSQL) just to have correct key=>value results. You really don't need to create table for that, just combination of SELECT, UNION, ... and you will get desired result.
2.) Use hidden variable which will be "translating" value to key, which will be used then in the query. E.g. https://community.grafana.com/t/how-to-alias-a-template-variable-value/10929/3
Of course everything has pros and cons, for example multi value variable values may not work as expecting.

How to convert json variable to table in postgresql

I have created a JSON type variable that looks like so, named group.
'{"SG1": ["2", "4"], "SG2": ["6", "8", "10"], "SG3": ["9"]}'
The idea is to create multiple values for a single key for example PF1 is a group (key) that has a list of values.
I want to create a table for such JSON variable that can give me output like,
group
values
PF1
2,4
PF2
6,8,10
PF3
9
The value column can be a string or comma-separated integer values, string is preferred.
I have tried
SELECT group ->> 'PF1' as group_1
from metadata;
Ths gives me a blank cell.
I am working with JSON in PostgreSQL for the first time so I have no idea about functions that might help me achieve this. Any help is appreciated.
It's not clear to me, what you are trying to achieve, but it seems you want each key/value pair as a row in the output:
select t.*
from metadata m
cross join jsonb_each_text(m."group") as t("group", values)
Online example
If your group column isn't jsonb but json you need to use json_each_text()
Note that group is reserved keyword and needs to be quoted every time you use it. It would be easier if you found a different name.

How to find an arbitrary key within a postgres jsonb object?

There are several operators in postgres for getting elements at a certain path in jsonb.
But how could I retrieve all the values that have a key of 'foo', if I don't know where in the whole object structure they will appear?
I saw there is a regex matches function which would return me matching regexes, but the object keyed off foo could be arbitrarily complex, so tough to come up with a regex that would pull the whole object out neatly?
Thanks for your help
SELECT jsonb_column->'foo'
FROM table
[WHERE jsonb_column ? 'foo'] -- ignore values without key "foo"