How do I most optimally do this N1QL SELECT query? - couchbase

Lets say I have a bunch of documents of type CONTACT:
{
"contactId": "V1234",
"contactFirstName": "A",
"contactLastName": "N",
"emailAddress": "12345",
"invitationId": "IVT:123",
"documentType": "CONTACT"
}
And for each contact document there is a EMAIL document and an INVITATION document:
EML:12345
{
"emailId": "12345",
"emailAddress" = ["abc#gmail.com"]
}
IVT:123
{
"invitationId": "IVT:123",
"invitationStatus": ["REGISTERED"]
}
Lets say I have an array of contactIds : ["V1234", "V2345" ... ]
How would I write a SELECT query for each contactId in that list and select contactFirstName, contactLastName, eml.emailAddress.[0], invitation.status.[0] (only if the status is of type "REGISTERED", or "INVITED".) and limit it to 10 values.
I was thinking something like:
SELECT DISTINCT
contact.contactFirstName as `contactFirstName`,
contact.contactLastName as `contactLastName`,
eml.emailAddress as `emailAddress`,
ivt.status[0].status AS invitationStatus
from
`contact-services` AS contact
INNER JOIN `contact-services` AS eml ON
CONCAT("EML",':',contact.contactEmailAddressIds[0]) =meta(eml).id
INNER JOIN `contact-services` AS ivt ON
contact.invitationId =meta(ivt).id
WHERE
contact.documentType="PERSON_CONTACT"
AND
ivt.status[0].status IN ["INVITED", "REGISTERED"]
and
contact.contactId IN ["V8459243"]

CREATE INDEX ix1 ON `contact-services` (contactId, emailAddress, invitationId, contactFirstName, contactLastName)
WHERE documentType = "CONTACT";
SELECT c.contactFirstName,
c.contactLastName,
(SELECT RAW e.emailAddress[0]
FROM contact-services` AS e USE KEYS ("EML:"||c.emailAddress))[0] AS emailAddress,
invt AS invitationStatus
FROM `contact-services` AS c
LET invt = (SELECT RAW i.invitationStatus
FROM `contact-services` AS i USE KEYS c.invitationId
WHERE ANY v IN i.invitationStatus SATISFIES v IN ["INVITED", "REGISTERED"] END)[0]
WHERE c.documentType = "CONTACT"
AND c.contactId IN ["V8459243"] AND
invt IS NOT MISSING
LIMIT 10;

Related

Postgresql join on jsonb array

I'm new to JSONB and I am wondering, if the following would be possible with a single query:
I have a lot of tables that look like this:
ID (INT) | members (JSONB)
all the tables has only one row.
example for 2 tables
table1:
id: 1
data:
[
{
"computer": "12.12.12.12",
"tag": "dog"
},
{
"computer": "1.1.1.1",
"tag": "cat"
},
{
"computer": "2.2.2.2",
"tag": "cow"
}
]
table2:
id: 1
data:
[
{
"IP address": "12.12.12.12",
"name": "Beni",
"address": "Rome"
},
{
"IP address": "1.1.1.1",
"name": "Jone",
"address": "Madrid"
}
]
The result should be rows like this :
computer
tag
name
12.12.12.12
dog
Beni
1.1.1.1
cat
Jone
Thanks !
Convert jsons into setof types using jsonb_to_recordset function and then join them (like they were relational tables).
with table1 (id,members) as (
values (1,'[{"computer": "12.12.12.12","tag": "dog"},{"computer": "1.1.1.1","tag": "cat"},{"computer": "2.2.2.2","tag": "cow"}]'::jsonb)
), table2 (id,members) as (
values (1,'[{"IP address": "12.12.12.12","name": "Beni", "address": "Rome"},{"IP address": "1.1.1.1","name": "Jone", "address": "Madrid"}]'::jsonb)
)
select t1.computer, t1.tag, t2.name
from jsonb_to_recordset((select members from table1 where id=1)) as t1(computer text,tag text)
join jsonb_to_recordset((select members from table2 where id=1)) as t2("IP address" text,name text)
on t1.computer = t2."IP address"
db fiddle
to get values out of a jsonb array of objects you somehow have to explode them.
another way with jsonb_array_elements:
with _m as (
select
jsonb_array_elements(members.data) as data
from members
),
_m2 as (
select
jsonb_array_elements(members2.data) as data
from members2
)
select
_m.data->>'computer' as computer,
_m.data->>'tag' as tag,
_m2.data->>'name' as name
from _m
left join _m2 on _m2.data->>'IP address' = _m.data->>'computer'
https://www.db-fiddle.com/f/68iC5TzLKbzkLZ8gFWYiLz/0

postgres select from json field as column for each key

I have Items (id, data (json)) table. Data column structure is this:
"somethingNotImportant":{
"someName":"Its a name",
"someProduct":"its a product"
},
"anotherNotImportant":{
"installments":null,
"baseRate":"30",
"grossComm":"20",
"totalMileage":null
},
"fleetdetails":{
"4b4bd441-a8eb-4754-9384-6f97d1ee23e3":{
"vehicleType":"43572386-5908-4e46-bf2b-3948df2e0e72",
"usage":"Class 3",
"carBand":"N\/A",
"coverType":"Third-Party Only",
"vehicleNumber":"1",
"modelRate":"222",
"technicalRate":"333",
"annualMileage":"444",
"adftExcess":"555",
"wsExcess":"777",
"annualBasePremium":null,
"usageRate":null
},
"cc12cc77-9346-4cae-8c27-6afc8b457f9b":{
"vehicleType":"fa999a90-b98f-499a-bef6-55b9a208c2fc",
"usage":"Class 1",
"carBand":"N\/A",
"coverType":"Comprehensive",
"vehicleNumber":"1",
"modelRate":"2",
"technicalRate":"3",
"annualMileage":"4",
"adftExcess":"5",
"wsExcess":"6",
"annualBasePremium":null,
"usageRate":null
}
}
}
I would like to select and get fleetdetails results like this:
item.id
vehicleType
usage
carBand
1
43572386-...
Class 3
N/A
1
fa999a90-...
Class 1
N/A
and so on.
How I can achieve this if I don't know fleetdetails json ids?
Combination of JSONB_EACH() and CROSS JOIN LATERAL will do the things for you try below query:
select
t1.id "id",
t2.value->>'vehicleType' "VEHICLETYPE",
t2.value->>'usage' "usage",
t2.value->>'carBand' "carBand",
t2.value->>'coverType' "coverType",
t2.value->>'vehicleNumber' "vehicleNumber",
t2.value->>'modelRate' "modelRate",
t2.value->>'technicalRate' "technicalRate",
t2.value->>'annualMileage' "annualMileage",
t2.value->>'adftExcess' "adftExcess",
t2.value->>'wsExcess' "wsExcess",
t2.value->>'annualBasePremium' "annualBasePremium",
t2.value->>'usageRate' "usageRate"
from items t1 cross join lateral jsonb_each(data->'fleetdetails') t2
DEMO
You can use jsonb_each():
select i.id,
d.detail ->> 'vehicleType' as vehicle_type,
d.detail ->> 'usage' as usage,
d.detail ->> 'carBand' as car_band
from item i
cross join jsonb_each(i.data -> 'fleetdetails') as d(key, detail);
This assumes that the column data is defined as jsonb (which it should be). If it's just a json column you have to use json_each() instead.

Count occurences along with result using DISTINCT ON on PostgreSQL

I have data like this:
[
{"name": "pratha", "email": "p#g.com", "sub": { "id": 1 } },
{"name": "john", "email": "x#x.com", "sub": { "id": 5 } },
{"name": "pratha", "email": "c#d.com", "sub": { "id": 2 } }
]
This is my query to get unique and latest emails:
SELECT DISTINCT ON (jae.e->>'name')
jae.e->>'name' as name,
jae.e->>'email' as email
FROM survey_results sr
CROSS JOIN LATERAL jsonb_array_elements(sr.data_field) jae (e)
ORDER BY jae.e->>'name', jae.e->'sub'->>'id' desc
Problem is, when I add count(*) to select, all counts are equal.
I want to get unique result with distinct, and count their occurrences. So in this case, pratha should be 2 and john should be 1
with their data (not just counts)
How can achieve this with PostgreSQL?
See here: https://dbfiddle.uk/?rdbms=postgres_11&fiddle=f5c640958c3e4d594287632d0f4a835f
Do you need this?
SELECT DISTINCT ON (jj->>'name') jj->>'name', jj->>'email' , count(*) over(partition by jj->>'name' )
from survey_results
join lateral jsonb_array_elements(data_field) j(jj) on true
ORDER BY jj->>'name', jj->'sub'->>'id' desc
https://dbfiddle.uk/?rdbms=postgres_11&fiddle=5f07b7bcb0001ebe32aa2f1338d9d0f0

Couchbase N1QL query sum from sub document array

I have the following document model in my couchbase db
{
type:"account"
id : "123",
transactions: [
{
type : "credit",
value : 100
},
{
type : "debit",
value : 10
}
]
}
How do i query all the account Ids and their sum of all credits ?
Using AS ARRAY functions https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/arrayfun.html
SELECT d.id,
ARRAY_SUM(ARRAY v.`value` FOR v IN d.transactions WHEN v.type = "credit" END) AS s
FROM default AS d
WHERE d.type = "account";
OR
Using subquery expression https://docs.couchbase.com/server/6.0/n1ql/n1ql-language-reference/subqueries.html
SELECT d.id,
(SELECT RAW SUM(d1.`value`)
FROM d.transactions AS d1
WHERE d1.type = "credit")[0] AS s
FROM default AS d
WHERE d.type = "account";

couchbase n1qlQuery Delete with sub-query

I have one bucket contain 2 types of objects:
first:
{
"id": "123"
"objectNamespace": "a",
"value": "value1"
}
second:
{
"id": "234",
"objectNamespace": "b",
"value": "value2",
"association": ["123"]
}
now I want to delete the document from type a only if does NOT have any associations from type b:
I try this:
DELETE FROM `bukcet_name`
WHERE objectNamespace = 'a'
AND id = "123"
AND NOT EXISTS (
SELECT *
WHERE ANY item IN bukcet_name.association
SATISFIES item = "123" END);
BUT this always delete the a doc with id 123
How can I do that?
There are a couple of mismatches between your data and your query.
(1) You are missing a FROM clause.
(2) You use associations instead of association.
(3) bucket_name.
Here is a possible query.
DELETE FROM `bucket_name`
WHERE objectNamespace = 'a'
AND id = "123"
AND NOT EXISTS (
SELECT * FROM bucket_name b2
WHERE ANY item IN b2.association
SATISFIES item = "123" END);