Create Couchbase Index on Array field - indexing

Hi how to create index on array field my sample doc is
{
"name": [ {
"family": "Smith",
"given": [
"Kam"
],
"prefix": [
"Mrs."
],
"use": "official"
},
{
"family": "Johns",
"given": [
"Kam"
],
"use": "maiden"
}
]
}
I want to write a search query (like) on family and given fields ...How to create a index and suggest query ..Im new to couchbase

This query that selects the customers with family name "Smith" and given name "Kam":
select * from customer
where any n in name satisfies n.family = 'Smith' and
any fn in n.given satisfies fn = 'Kam' end end
Note the use of a nested ANY clause because of the use of a nested array in the data.
You can then create an index on the family name like this:
CREATE INDEX customer_name ON customer
( DISTINCT ARRAY n.family FOR n IN name END)
The index gets used without any hints. You can see that it is being used by adding EXPLAIN to the beginning of the query. That will get you a query plan in JSON that includes an index scan operator.
You can learn more about array indexing here:
https://developer.couchbase.com/documentation/server/current/n1ql/n1ql-language-reference/indexing-arrays.html

Related

how to use trino/presto to query redis

I have a simple string and hash stored in redis
get test
"1"
hget htest first
"first hash"
I'm able to see the "table" test, but there are no columns
trino> show columns from redis.default.test;
Column | Type | Extra | Comment
--------+------+-------+---------
(0 rows)
and obviously I can't get result from select
trino> select * from redis.default.test;
Query 20210918_174414_00006_dmp3x failed: line 1:8: SELECT * not allowed from relation
that has no columns
I see in the documentation that I might need to create a table definition file, but I wasn't able to create one that will work.
I had few variations of this, but this is the one for example:
{
"tableName": "test",
"schemaName": "default",
"value": {
"dataFormat": "json",
"fields": [
{
"name": "number",
"mapping": 0,
"type": "INT"
}
]
}
}
any idea what am I doing wrong?
I focused on the string since it's simpler, but I also need to query the hash

jsonb find a value in an array

There is such a data structure:
Column "recipient" type jsonb
{
"phoneNumbers": [
{
"isDefault": true,
"type": "MOBILE",
"number": "3454654645"
},
{
"isDefault": true,
"type": "MOBILE",
"number": "12423543645"
}
]
}
I need to write a search request by number. In the postgres documentation, I did not find a search by value in an array, only it is obtained by an index. It doesn't suit me
I made a query like this, it gets executed, but are there any other ways to search through an array?
SELECT *
FROM my_table
WHERE recipient -> 'phoneNumbers' #> '[{"number":3454654645}]'
That's pretty much the best way, yes.
If you have a (GIST) index on recipient the index would not be used by your condition. But the following could make use of such an index:
SELECT *
FROM my_table
WHERE recipient #> '["phoneNumbers": {"number":3454654645}]}'
If you are using Postgres 12 or later, you can also use a JSON path expression:
SELECT *
FROM my_table
WHERE recipient ## '$.phoneNumbers[*].number == "12423543645"'
If you can't pass a JSON object to your query, you can use an EXISTS sub-select:
SELECT mt.*
FROM my_table mt
WHERE EXISTS (SELECT *
FROM jsonb_array_elements_text(mt.recipient -> 'phoneNumbers') as x(element)
WHERE x.element ->> 'number' = '3454654645')
The '3454654645' can be passed as a parameter to your query. This will never make use of an index though.

Query a column with jsonb data meeting certain criteria

Problem
I have a table like this:
product
tags (jsonb)
P001
[{"name": "LX","active": true}, {"name": "TX","active": true}]
P002
[{"name": "LX","active": true}]
I am trying to query against this table to get a list of products with tags that are the same.
I found the following to be insufficient for my query since it will match all products with at least the tag I query for:
SELECT product
FROM product_table
WHERE tags #> '[
{"name": "LX","active": true}
]';
Result
product
P001
P002
So I need the match to be more exact without being so strict as to demand order of tag objects in the array. For example:
[
{
"name": "LX",
"active": true
},
{
"name": "TX",
"active": true
}
]
-- Interpreted the same as
[
{
"name": "TX",
"active": true
},
{
"name": "LX",
"active": true
}
]
Desired Result
A list of products that match only the tags in the query.
Resources
A list of the resources I am using to try and solve the problem.
9.16. JSON Functions and Operators
How To Query a JSONB Array of Objects as a Recordset in PostgreSQL
Working with a JSONB Array of Objects in PostgreSQL
Base on the example you give, you can use simultaneous containment in both directions.
...WHERE tags <# :whatever and tags #> :whatever
If you don't like repeating the arguments, you could make a custom function, or operator:
create function equal_but_for_order(jsonb,jsonb) returns boolean language sql as $$
select $1 <# $2 and $1 #> $2
$$;
create operator <#> (function = equal_but_for_order, leftarg = jsonb, rightarg=jsonb);
...WHERE tags <#> :whatever

How to check if json array already contains a certain key?

Let's say I have this json in my jsonb column
{
"fields": [
{
"name": "firstName",
},
{
"name": "lastName",
},
...
}
How can I know if the "firstName" already exist?
I've tried this so far
SELECT field->>'fields'
from person where (field->'name')::jsonb ? 'firstName';
Use the containment operator #>:
select field->>'fields'
from person
where field->'fields' #> '[{"name": "firstName"}]'
you can use json_array_elements to generate fields elements so you can filter based on 'name'.
SELECT field->>'fields', obj.*
from person, jsonb_array_elements_text(field->'fields') obj
where obj = '{"name": "firstName"}'
see dbfiddle

jsonb LIKE query on nested objects in an array

My JSON data looks like this:
[{
"id": 1,
"payload": {
"location": "NY",
"details": [{
"name": "cafe",
"cuisine": "mexican"
},
{
"name": "foody",
"cuisine": "italian"
}
]
}
}, {
"id": 2,
"payload": {
"location": "NY",
"details": [{
"name": "mbar",
"cuisine": "mexican"
},
{
"name": "fdy",
"cuisine": "italian"
}
]
}
}]
given a text "foo" I want to return all the tuples that have this substring. But I cannot figure out how to write the query for the same.
I followed this related answer but cannot figure out how to do LIKE.
This is what I have working right now:
SELECT r.res->>'name' AS feature_name, d.details::text
FROM restaurants r
, LATERAL (SELECT ARRAY (
SELECT * FROM json_populate_recordset(null::foo, r.res#>'{payload,
details}')
)
) AS d(details)
WHERE d.details #> '{cafe}';
Instead of passing the whole text of cafe I want to pass ca and get the results that match that text.
Your solution can be simplified some more:
SELECT r.res->>'name' AS feature_name, d.name AS detail_name
FROM restaurants r
, jsonb_populate_recordset(null::foo, r.res #> '{payload, details}') d
WHERE d.name LIKE '%oh%';
Or simpler, yet, with jsonb_array_elements() since you don't actually need the row type (foo) at all in this example:
SELECT r.res->>'name' AS feature_name, d->>'name' AS detail_name
FROM restaurants r
, jsonb_array_elements(r.res #> '{payload, details}') d
WHERE d->>'name' LIKE '%oh%';
db<>fiddle here
But that's not what you asked exactly:
I want to return all the tuples that have this substring.
You are returning all JSON array elements (0-n per base table row), where one particular key ('{payload,details,*,name}') matches (case-sensitively).
And your original question had a nested JSON array on top of this. You removed the outer array for this solution - I did the same.
Depending on your actual requirements the new text search capability of Postgres 10 might be useful.
I ended up doing this(inspired by this answer - jsonb query with nested objects in an array)
SELECT r.res->>'name' AS feature_name, d.details::text
FROM restaurants r
, LATERAL (
SELECT * FROM json_populate_recordset(null::foo, r.res#>'{payload, details}')
) AS d(details)
WHERE d.details LIKE '%oh%';
Fiddle here - http://sqlfiddle.com/#!15/f2027/5