How to query inside a postgres db having one column as json value - postgresql

I have a table named Test and in that one column (Subject) contains JSON values.
This is the query which i am using
select Name,Subject
from Test
where id =1;
And the following are the JSON values present inside table.
{
"subject":{
"Maths":"20",
"Physics":"21",
"English":"22"
},
"Staff":{
"English":"Anna",
"maths":"Rahul",
"Physics":"John"
}
}
Now my question is how to write a query to get English mark from JSON value.
Expected o/p is 22.
I am new to postgres, can any one help me in this thanks in advance

You can combine the -> and ->> operators
select Name,Subject, subject -> 'subject' ->> 'English' as english_mark
from Test
where id =1;
Alternatively use the #>> operator where you provide the path to the element you want as an array of keys:
select Name,Subject, subject #>> '{subject, English}' as english_mark
from Test
where id =1;

Related

How can I compare json field with a string value in postgresql?

I have a field payload saved in a postgresql table which is json type. This type has a nested field subcategory which is string. Below is the output of this value:
=> select payload->'subcategory' from "Merchant";
?column?
-------------------------------
"Food"
null
"AUTOMOTIVE"
null
"MEDICAL"
null
null
"CLUB"
"Petrol Stations"
However, I can't put this field in the where clause. Below query returns 0 rows. But from above output it shows there are rows whose value is CLUB. What is the right way to use json field in where clause?
=> select count(*) from "Merchant" where ("payload"->'subcategory')::text = 'CLUB';
count
-------
0
Figured out what's wrong, I need to use ->> in the where like "payload"->'subcategory'.
that because ->> converts it to text while -> makes it as JSONB
An alternative solution is to use the JSON contains operator #>:
select count(*)
from "Merchant"
where payload #> '{"subcategory": "CLUB")';

Build jsonb array from jsonb field

I have column options with type jsonb , in format {"names": ["name1", "name2"]} which was created with
UPDATE table1 t1 SET options = (SELECT jsonb_build_object('names', names) FROM table2 t2 WHERE t2.id= t1.id)
and where names have type jsonb array.
SELECT jsonb_typeof(names) FROM table2 give array
Now I want to extract value of names as jsonb array. But query
SELECT jsonb_build_array(options->>'names') FROM table
gave me ["[\"name1\", \"name2\"]"], while I expect ["name1", "name2"]
How can I get value in right format?
The ->> operator will return the value of the field (in your case, a JSON array) as a properly escaped text. What you are looking for is the -> operator instead.
However, note that using the jsonb_build_array on that will return an array containing your original array, which is probably not what you want either; simply using options->'names' should get you what you want.
Actually, you don't need to use jsonb_build_array() function.
Use select options -> 'names' from table; This will fix your issue.
jsonb_build_array() is for generating the array from jsonb object. You are following wrong way. That's why you are getting string like this ["[\"name1\", \"name2\"]"].
Try to execute this sample SQL script:
select j->'names'
from (
select '{"names": ["name1", "name2"]}'::JSONB as j
) as a;

Parse jsonb field - PostgreSQL

I have a field that is of type jsonb in a PostgreSQL database.
Example:
{"timestamp":"2016-12-14T04:15:04.836Z","receiptResult":{"status":"successful","timestamp":"2016-12-14T04:15:04.739Z","notes":"Customer Accepted"}}
How can I only return the "notes" in a select statement, I've tried:
SELECT data::json->>'notes' as notes
But nothing is returned, if I use:
SELECT data::json->'receiptResult' as notes;
It returns:
{"status":"successful","timestamp":"2016-114T04:15:04.739Z","notes":"Customer Accepted"}
But I only need the text after "notes".
Inside key receiptResult has another JSON object, you cannot access it in top-level. Try this:
WITH sample AS (
SELECT '{"timestamp":"2016-12-14T04:15:04.836Z","receiptResult":{"status":"successful","timestamp":"2016-12-14T04:15:04.739Z","notes":"Customer Accepted"}}'::jsonb AS my_column
)
SELECT my_column->'receiptResult'->>'notes' FROM sample;
As you can see, -> operator returns value as a JSONB and ->> operator returns as a text.
More info here.

AR Query for jsonb attribute column

I'm using Postgres for my db, and I have a column in my Auction model as a jsonb column. I want to create a query that searches the Auction's json column to see whether a user's name OR email exists in any Auction instance's json column.
Right now I have #auctions = Auction.where('invitees #> ?', {current_user.name.downcase => current_user.email.downcase}.to_json), but that only brings back exact key => value matches I want to know whether the name OR the email exists.
You're using the #> operator. The description for it is this:
“Does the left JSON value contain the right JSON path/value entries
at the top level?”
You probably want the ? operator if you want to return a row when the key (name in your case) matches.
There's not a good way to search for values only in a JSON column (see this answer for more details), but you could check if the key exists alone or the key and value match exists.
The same ActiveRecord methods and chaining apply as when using non-JSON columns, namely where and where(…).or(where(…)):
class Auction
def self.by_invitee(user)
name = user.name.downcase
json = { name => user.email } # note: you should be downcasing emails anyways
where('invitee ? :name', name: name).or(
where('invitee #> :json', json: json)
)
end
end
This is just a temporary patch until I add an Invite model, but casting the invitee column to text I can search the columns. Like so
SELECT * FROM auctions
WHERE data::text LIKE "%#{string I'm searching for}%"
So, AR:
Auction.where('data::text LIKE ?', "%#{string I'm searching for}%")

querying JSONB with array fields

If I have a jsonb column called value with fields such as:
{"id": "5e367554-bf4e-4057-8089-a3a43c9470c0",
"tags": ["principal", "reversal", "interest"],,, etc}
how would I find all the records containing given tags, e.g:
if given: ["reversal", "interest"]
it should find all records with either "reversal" or "interest" or both.
My experimentation got me to this abomination so far:
select value from account_balance_updated
where value #> '{}' :: jsonb and value->>'tags' LIKE '%"principal"%';
of course this is completely wrong and inefficient
Assuming you are using PG 9.4+, you can use the jsonb_array_elements() function:
SELECT DISTINCT abu.*
FROM account_balance_updated abu,
jsonb_array_elements(abu.value->'tags') t
WHERE t.value <# '["reversal", "interest"]'::jsonb;
As it turned out you can use cool jsonb operators described here:
https://www.postgresql.org/docs/9.5/static/functions-json.html
so original query doesn't have to change much:
select value from account_balance_updated
where value #> '{}' :: jsonb and value->'tags' ?| array['reversal', 'interest'];
in my case I also needed to escape the ? (??|) because I am using so called "prepared statement" where you pass query string and parameters to jdbc and question marks are like placeholders for params:
https://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html