Searching for empty string in SphinxQL - sphinx

I have a string field 'extra_data' in Sphinx index, which has data in comma-separated format (ex. 'green', 'red', 'green,red', ...). And I need to select to find rows:
1. extra_data is 'green'
2. or extra_data is 'red'
3. or extra_data is empty
So I can write query:
SELECT id FROM sphinx WHERE MATCH('#extra_data (^green$|^red$))')
But how should I write query to find empty extra_data ('') too?

Sphinx doesnt 'index' nothing. It indexes words :)
So you have to arrange for empty to be a word that can be indexed.
eg for a database backed index..
sql_query = SELECT id,title, ... , IF(extra_data='','_empty',extra_data) AS extra_data FROM mytable ...
Then can do
... WHERE MATCH('#extra_data (^green$|^red$|_empty)')

Related

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 replace substring in Postgres

I want to replace substrings in PostgreSQL.
For example string "ABC_dog" , 'dogABCcat', 'dogABC' to 'XYZ_dog', 'dogXYZcat', 'dogXYZ'
I tried:
UPDATE my_table SET name = regexp_replace( name , '.*ABC.*', '.*XYZ.*', 'g')
but it set new names to '.XYZ.'
The simplest solution would be to use the replace() function:
UPDATE my_table SET name = replace(name , 'ABC', 'XYZ');
Keep in mind, though, that this will replace all rows in your table. Unless most rows have the pattern you want to replace, you are better off testing for the offending sub-string first:
UPDATE my_table SET name = replace(name , 'ABC', 'XYZ')
WHERE position('ABC' in name) > 0;
The pattern '.*' matches everything, so '.ABC.' means match everything before the ABC, the ABC and everything after as well, so effectively the whole string.
Change it to be just ABC as that is the bit you want to replace. Also, remove the .* from the replacement.
UPDATE my_table SET name = regexp_replace( name , 'ABC', 'XYZ', 'g')

How get name of table in result array in Sphinx?

I use some indexes in one file sphinx.conf. When I give result array from these indexes(different tables Mysql) I don't get names of tables. How I can get it?
You can modify sql_query attribute of your indexes in sphinx.conf so they will return one fake attribute - index name.
For example:
first_idx:
...
sql_query = SELECT <...>, 'first_idx' as index_name FROM fisrt_table;
second_idx:
...
sql_query = SELECT <...>, 'second_idx' as index_name FROM second_table;

How to search in SphinxQL by sql_attr_multi field

This is my query to sphinxQL:
SELECT option_id FROM items WHERE cat IN (10,11) GROUP BY option_id LIMIT 100000 OPTION max_matches=100000
cat is sql_attr_multi field, this query not return to me correct result. Anybody knows how to search by fields by this sphinx attribute?
That query looks for items where cat attribute contains either 10 OR 11, is that what you trying to do?
If its not, would help to know what you are trying to query!
I had similar problem.
When I pass array to IN condition for MVA attribute I have no result, however there is several ones in index.
When I debug condition (attribute array(10, 11) in you case) I see that array values is string integer instead.
array(
0 => "10",
1 => "11"
)
For every single value in condition uses quoteArr() function
https://github.com/FoolCode/SphinxQL-Query-Builder/blob/master/src/SphinxQL.php#L518
wich escape value according with https://github.com/FoolCode/SphinxQL-Query-Builder/blob/master/src/Drivers/ConnectionBase.php#L95
The quote function use is_int() PHP internal function:
$a = "1";
var_dump(is_int($a)); // return bool(false)
It mean, thet instead
cat IN (10, 11)
you have
cat IN ("10", "11")
But sphinx can't filter MVA attribute by not integer (string) values no metter IN or OR WHERE notation you use.
[1064] index document : unsupported filter type 'string' on MVA column [ SELECT * FROM `document` WHERE MATCH('(some query)') AND `_category` = '5' LIMIT 0, 10]
You should use strict value type:
foreach ($category as &$item) {
$item = (int)$item;
} unset($item);
I am not sure that it is your incindent. Unfortunately, there isn't enough data to say it for sure in this case.

Best way to search in postgres by a group of keyword

right now I have a keyword array like:
['key1', 'key2', 'key3'.......] , the keyword can be number or character.
If I want to search in my table (postgres database), and find out all record contain any of keyword in that array, how can I do that?
For example:
I got a table which has a column called name and a column called description
I need find all record that either name or description contains any keywords in that array.
thanks
Maybe this example will be useful:
CREATE TABLE TEST(
FIELD_KEY TEXT);
INSERT INTO TEST VALUES('this is hello');
INSERT INTO TEST VALUES('hello');
INSERT INTO TEST VALUES('this');
INSERT INTO TEST VALUES('other message');
SELECT *
FROM TEST
WHERE FIELD_KEY LIKE ANY (array['%this%', '%hel%']);
This will return:
this is hello
hello
this
Here other example:
SELECT *
FROM TEST
WHERE FIELD_KEY ~* 'this|HEL';
~* is case insensitive, ~ is case sensitive
You can try this example here.
select *
from t
where
array[name] <# my_array
or array[description] <# my_array
Couple the like operator with the any subquery expression:
select *
from t
where name like any (values ('%John%'), ('%Mary%'))
Or the array syntax:
where name like any (array['%John%', '%Mary%'])