How to filter JSON in SphinxQL? - sphinx

I have a JSON field with a simple numeric array
[46,70,34]
How can I filter query selecting only those rows where present let's say '70' in a JSON field? Something similar to JSON_CONTAINS in MySQL.
I have already tried
SELECT id, name, IN(tags, '70') AS c FROM index WHERE c = 1;
and
SELECT id, name, ALL(var='70' FOR var IN tags) as c FROM index WHERE c=1;
But it doesn't work.

Actully think...
SELECT id, name FROM index WHERE tags = 70;
should just work. JSON arrays, end up working 'like' a MVA.
Otherwise, you would want ANY() (not ALL()), because only one of the values in the JSON array would be 70, not all of them (46 wouldn't match for example!)
SELECT id, name, ANY(var=70 FOR var IN tags) as c FROM index WHERE c=1;
(finally as a numeric value, shouldn't be quoted!)

Related

Get unique values from PostgreSQL array

This seems like it would be straightforward to do but I just can not figure it out. I have a query that returns an ARRAY of strings in one of the columns. I want that array to only contain unique strings. Here is my query:
SELECT
f."_id",
ARRAY[public.getdomain(f."linkUrl"), public.getdomain(f."sourceUrl")] AS file_domains,
public.getuniqdomains(s."originUrls", s."testUrls") AS source_domains
FROM
files f
LEFT JOIN
sources s
ON
s."_id" = f."sourceId"
Here's an example of a row from my return table
_id
file_domains
source_domains
2574873
{cityofmontclair.org,cityofmontclair.org}
{cityofmontclair.org}
I need file_domains to only contain unique values, IE a 'set' instead of a 'list'. Like this:
_id
file_domains
source_domains
2574873
{cityofmontclair.org}
{cityofmontclair.org}
Use a CASE expression:
CASE WHEN public.getdomain(f."linkUrl") = public.getdomain(f."sourceUrl")
THEN ARRAY[public.getdomain(f."linkUrl")]
ELSE ARRAY[public.getdomain(f."linkUrl"), public.getdomain(f."sourceUrl")]
END

Extract all the values in jsonb into a row

I'm using postgresql 11, I have a jsonb which represent a row of that table, it's look like
{"userid":"test","rolename":"Root","loginerror":0,"email":"superadmin#ae.com",...,"thirdpartyauthenticationkey":{}}
is there any method that I could gather all the "values" of the jsonb into a string which is separated by ',' and without the keys?
The string I want to obtain with the jsonb above is like
(test, Root, 0, superadmin#ae.com, ..., {})
I need to keep the ORDER of those values as what their keys were in the jsonb. Could I do that with postgresql?
You can use the jsonb_populate_record function (assuming your json data does match the users table). This will force the text value to match the order of your users table:
Schema (PostgreSQL v13)
CREATE TABLE users (
userid text,
rolename text,
loginerror int,
email text,
thirdpartyauthenticationkey json
)
Query #1
WITH d(js) AS (
VALUES
('{"userid":"test", "rolename":"Root", "loginerror":0, "email":"superadmin#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb),
('{"userid":"other", "rolename":"User", "loginerror":324, "email":"nope#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb)
)
SELECT jsonb_populate_record(null::users, js),
jsonb_populate_record(null::users, js)::text AS record_as_text,
pg_typeof(jsonb_populate_record(null::users, js)::text)
FROM d
;
jsonb_populate_record
record_as_text
pg_typeof
(test,Root,0,superadmin#ae.com,{})
(test,Root,0,superadmin#ae.com,{})
text
(other,User,324,nope#ae.com,{})
(other,User,324,nope#ae.com,{})
text
Note that if you're building this string to insert it back into postgresql then you don't need to do that, since the result of jsonb_populate_record will match your table:
Query #2
WITH d(js) AS (
VALUES
('{"userid":"test", "rolename":"Root", "loginerror":0, "email":"superadmin#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb),
('{"userid":"other", "rolename":"User", "loginerror":324, "email":"nope#ae.com", "thirdpartyauthenticationkey":{}}'::jsonb)
)
INSERT INTO users
SELECT (jsonb_populate_record(null::users, js)).*
FROM d;
There are no results to be displayed.
Query #3
SELECT * FROM users;
userid
rolename
loginerror
email
thirdpartyauthenticationkey
test
Root
0
superadmin#ae.com
[object Object]
other
User
324
nope#ae.com
[object Object]
View on DB Fiddle
You can use jsonb_each_text() to get a set of a text representation of the elements, string_agg() to aggregate them in a comma separated string and concat() to put that in parenthesis.
SELECT concat('(', string_agg(value, ', '), ')')
FROM jsonb_each_text('{"userid":"test","rolename":"Root","loginerror":0,"email":"superadmin#ae.com","thirdpartyauthenticationkey":{}}'::jsonb) jet (key,
value);
db<>fiddle
You didn't provide DDL and DML of a (the) table the JSON may reside in (if it does, that isn't clear from your question). The demonstration above therefore only uses the JSON you showed as a scalar. If you have indeed a table you need to CROSS JOIN LATERAL and GROUP BY some key.
Edit:
If you need to be sure the order is retained and you don't have that defined in a table's structure as #Marth's answer assumes, then you can of course extract every value manually in the order you need them.
SELECT concat('(',
concat_ws(', ',
j->>'userid',
j->>'rolename',
j->>'loginerror',
j->>'email',
j->>'thirdpartyauthenticationkey'),
')')
FROM (VALUES ('{"userid":"test","rolename":"Root","loginerror":0,"email":"superadmin#ae.com","thirdpartyauthenticationkey":{}}'::jsonb)) v (j);
db<>fiddle

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

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;

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;

Postgres update first record in JSON column for all records

I'm using postgres 9.6.1.
I have an "orders" table that has a column "orderData" that is type JSON.
What each record in the orderData column currently looks like:
[{"orderId":1}, {"orderId":2}, {"orderId":3}]
I'm trying to write a sql query that adds a key to the first order object in each array.
What each record in the orderData column should look like after query:
[{"orderId":1, "isFirstOrder": true}, {"orderId":2}, {"orderId":3}]
NOT WORKING ATTEMPT:
WITH order AS (
SELECT orderData
FROM orders
CROSS APPLY OPENJSON(c) s
WHERE i = 1
)
UPDATE order
SET c = JSON_MODIFY(c, 'isFirstOrder', 'true');
Any help would be greatly appreciated.
demo:db<>fiddle
UPDATE orders
SET c = jsonb_set(c, '{0}', c -> 0 || '{"isFirstOrder": true}');
c -> 0 gets the first element of your array
|| adds the new attribute
jsonb_set rewrites the elements if they exists whereas {0} locates the rewriting position within the array
Postgres JSON functions
For type json there's no function json_set. So you have to do a bit of casting around your json data into jsonb and the final result back into json:
UPDATE orders
SET c = jsonb_set(c::jsonb, '{0}', c::jsonb -> 0 || '{"isFirstOrder": true}')::json
demo:db<>fiddle