How to pass a variable into Subquery with n1ql? - couchbase

In my situation, entreprise(company) can have several sites(filiales), I want to get all the filiales with format array.
In the json entreprise(company), there is no information of sites(filiales), In the json sites(filiales), it has entreprise(company) uid.
Json entreprise(company):
{
"type": "entreprise",
"dateUpdate": 1481716305279,
"owner": {
"type": "user",
"uid": "PNnqarPqSdaxmEJ4DoMv-A"
}
}
Json sites(filiales):
{
"type": "site",
"entreprise": {
"uid": "3c0CstzsTjqPdycL5yYzJQ",
"type": "entreprise"
},
"nom": "test"
}
The query I tried:
SELECT
META(entreprise).id as uid,
ARRAY s FOR s IN (SELECT d.* FROM default d WHERE d.type = "site" AND d.entreprise.uid = uid) END as sites,
entreprise.*
FROM default entreprise
WHERE entreprise.type = "entreprise";
Result: error
{
"code": 5010,
"msg": "Error evaluating projection. - cause: FROM in correlated subquery must have USE KEYS clause: FROM default."
}
Then i use alias:
SELECT
META(entreprise).id as uid,
ARRAY s FOR s IN (SELECT d.* FROM default d WHERE d.type = "site" AND d.entreprise.uid = META(entreprise).id) END as sites,
entreprise.*
FROM default entreprise
WHERE entreprise.type = "entreprise";
Result: sites array is empty.

First you have to create an index on your site documents :
CREATE INDEX site_ent_idx ON default(entreprise.uid) WHERE type="site";
Then change your query to use the new index :
SELECT
META(entreprise).id as uid,
ARRAY s FOR s IN (
SELECT site.*
FROM default as ent USE KEYS META(entreprise).id
JOIN default as site ON KEY site.entreprise.uid FOR ent
) END as sites,
entreprise.*
FROM default entreprise
WHERE entreprise.type = "entreprise"
This solution should meet your needs.

You need to perform an index join from sites to enterprises. See https://dzone.com/articles/join-faster-with-couchbase-index-joins
After that, use GROUP BY and ARRAY_AGG() to collect the sites into arrays.

Related

How to query multiplte row in one json object

table provider
table provider_properties
here I wanted the result something like
{
"provider_uuid": "b897f790-ee90-4869-9345-690380b1a0c9",
"name": "Provider 1",
"password": "112233",
"username": "provider_1",
"properties": {
"address_1": "Dubai",
"address_2": "NY"
}
}
here i tried something like
SELECT provider.*, json_object(provider_properties.key_name, provider_properties.key_value) as properties FROM provider JOIN provider_properties on provider.provider_id = provider_properties.provider_uuid;
but the problem is i am getting 2 rows
Since your expected results need specific formatting in json. You want to refer to JSON Formatted output. This is for shell though.
You might also want to try this...
This would give you a tabular results but in one row.
SELECT
provider.*,
p_props.properties
FROM provider
JOIN (
provider_uuid,
SELECT JSON_OBJECTAGG(
provider_properties.key_name,
provider_properties.key_value
) as properties
FROM provider_properties
GROUP BY provider_uuid
) p_props ON provider.provider_id = p_props.provider_uuid;
CONCAT() and REPLACE() here are used for sorting the order of columns.
I would say the use of REPLACE() here is quite risky, please test it out and see how it goes.
db<>fiddle
SELECT
p.*,
CONCAT(
'{"', 'provider_uuid": "', pp.provider_uuid, '"',
REPLACE(JSON_OBJECT('name', p.name, 'password', p.password,
'username', p.username, 'properties', pp.name_value), '{"name', ', "name')
) AS your_json
FROM provider p
JOIN (
SELECT provider_uuid, JSON_OBJECTAGG(key_name, key_value) as name_value
FROM provider_properties
GROUP BY provider_uuid
) pp ON p.provider_id = pp.provider_uuid;

Need to convert the SQL Query to Gorm query

I have this SQL query
Select CONCAT(kafka_user_stream.FirstName,' ', kafka_user_stream.LastName) AS "Full Name",
kafka_user_stream.UID AS "User ID",
kafka_user_stream.CountryCode AS "Country",
kafka_user_stream.CreatedAt AS "Registration Date & Time",
COUNT(jackpotmessage_stream.UID) AS "Win Count"
FROM kafka_user_stream LEFT JOIN
jackpotmessage_stream ON jackpotmessage_stream.UID = kafka_user_stream.UID
WHERE "Type"='goldenTicketWin'
GROUP BY "Full Name", "User ID", "Country", "Registration Date & Time"
ORDER BY "Win Count" DESC
I want to convert it to Gorm. I can use it using
err = s.db.Exec("...QUERY")
but i cannot extract data from the above query. I need to extract all of the above fields (Full Name, User ID etc) and store them in a struct.
In above query, kafka_user_stream and jackpot_message are the tables extracted from a kafka stream. I am using go-gorm and go.
I tried the Gorm documentation as well as few other references but I am unable to find any solution. Would be very thankful for any leads, insight or help.
With native go/mysql driver, you should use Query() and Scan() methods to get results from the database and store them in a struct, not Exec().
In GORM, you can use SQL Builder for your custom queries:
type Result struct {
ID int
Name string
Age int
}
var result Result
db.Raw("SELECT id, name, age FROM users WHERE name = ?", 3).Scan(&result)
I figured out a slightly different way as suggested by Aykut which works fine.
rows, _err := s.gdb.Raw(`Select CONCAT(kafka_user_stream.FirstName,' ', kafka_user_stream.LastName) AS "FullName",
kafka_user_stream.UID AS "UserID",
kafka_user_stream.CountryCode AS "Country",
kafka_user_stream.CreatedAt AS "CreatedAt",
COUNT(jackpotmessage_stream.UID) AS "WinCount"
FROM kafka_user_stream LEFT JOIN
jackpotmessage_stream ON jackpotmessage_stream.UID = kafka_user_stream.UID
WHERE "Type"='goldenTicketWin'
GROUP BY "FullName", "UserID", "Country", "CreatedAt"
ORDER BY "WinCount" DESC;`).Rows()

Find match item in JSON array

I have a SQL table called 'Interactions' and a column called Events that holds an array of JSON data. I am looking for any row where the Events json has any array with #odata.type = #Sitecore.XConnect.Goal
[
{
"#odata.type":"#Sitecore.XConnect.Collection.Model.PageViewEvent",
"CustomValues":[
],
"DefinitionId":"9326cb1e-cec8-48f2-9a3e-91c7dbb2166c",
"ItemId":"5ae02a76-ac59-4dbb-913f-3b2e51d92bae",
"Id":"b067f72f-1d60-4773-a2e8-9d23770fea54",
"Timestamp":"2019-11-11T17:18:31.2206225Z",
"ItemLanguage":"en",
"ItemVersion":1,
"Url":"/renewal-confirmation",
"SitecoreRenderingDevice":{
"Id":"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3",
"Name":"Default"
}
},
{
"#odata.type":"#Sitecore.XConnect.Goal",
"CustomValues":[
],
"DataKey":"/sitecore/content/Client/home/renewal-confirmation",
"DefinitionId":"c0bc91b9-b5fc-4faa-bc12-3dba8bbae44f",
"ItemId":"5ae02a76-ac59-4dbb-913f-3b2e51d92bae",
"EngagementValue":100,
"Id":"e7031fb4-ce57-459f-a9f1-2682748d3431",
"ParentEventId":"b067f72f-1d60-4773-a2e8-9d23770fea54",
"Timestamp":"2019-11-11T17:18:31.2518732Z"
}
]
What I am currently trying is this, but no results
select *
from [Interactions] I
where exists
(
select *
from openjson(I.Events,'$."#odata.type"')
where value = '#Sitecore.XConnect.Goal'
)
If I use this, I can get any row where the 1st item in the array #odata.type = #Sitecore.XConnect.Goal. This works. But I want it from any item in the array.
SELECT *
FROM [Interactions]
WHERE JSON_VALUE([Events], '$[0]."#odata.type"') = '#Sitecore.XConnect.Goal'
One possible approach is to parse the JSON column using OPENJSON() with explicit schema (WITH clause with columns definitions). With this approach you can filter the Interactions table and get information from the JSON data.
Table:
CREATE TABLE Interactions (
Events nvarchar(max)
)
INSERT INTO Interactions
(Events)
VALUES
(N'[
{
"#odata.type":"#Sitecore.XConnect.Collection.Model.PageViewEvent",
"CustomValues":[
],
"DefinitionId":"9326cb1e-cec8-48f2-9a3e-91c7dbb2166c",
"ItemId":"5ae02a76-ac59-4dbb-913f-3b2e51d92bae",
"Id":"b067f72f-1d60-4773-a2e8-9d23770fea54",
"Timestamp":"2019-11-11T17:18:31.2206225Z",
"ItemLanguage":"en",
"ItemVersion":1,
"Url":"/renewal-confirmation",
"SitecoreRenderingDevice":{
"Id":"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3",
"Name":"Default"
}
},
{
"#odata.type":"#Sitecore.XConnect.Goal",
"CustomValues":[
],
"DataKey":"/sitecore/content/Client/home/renewal-confirmation",
"DefinitionId":"c0bc91b9-b5fc-4faa-bc12-3dba8bbae44f",
"ItemId":"5ae02a76-ac59-4dbb-913f-3b2e51d92bae",
"EngagementValue":100,
"Id":"e7031fb4-ce57-459f-a9f1-2682748d3431",
"ParentEventId":"b067f72f-1d60-4773-a2e8-9d23770fea54",
"Timestamp":"2019-11-11T17:18:31.2518732Z"
}
]')
Statement:
SELECT *
FROM Interactions i
CROSS APPLY OPENJSON(i.Events) WITH (
ODataType nvarchar(100) '$."#odata.type"'
-- and additional columns definitions
) j
WHERE j.ODataType = '#Sitecore.XConnect.Goal'
Your original query is close but doesn't work because you can't directly pick out scalars with OPENJSON. You want something like this:
SELECT *
FROM [interactions]
WHERE EXISTS (
SELECT 1
FROM OPENJSON([events]) WITH (
[#odata.type] NVARCHAR(MAX)
)
WHERE [#odata.type] = '#Sitecore.XConnect.Goal'
)

How to write one n1ql query to sum values from multiple documents in the same bucket

I am a newbie to Couchbase DB server and I am trying to achieve with one query what I have done with three queries as this is not so efficient.
I have three different documents types (x,y,z) in the same bucket; all having a similar key: 'district' like so:
document x:
{
"type": "x",
"district": "Some district"
}
document y:
{
"type": "y",
"district": "Some district"
}
document z:
{
"type": "z",
"district": "Some district"
}
I have currently implemented something like the following pseudo-code in PHP:
$totalDistrictInX = "SELECT COUNT(x) FROM bucket WHERE type = 'x' AND district = 'Maboro';
$totalDistrictInY = "SELECT COUNT(x) FROM bucket WHERE type = 'y' AND district = 'Maboro';
$totalDistrictInZ = "SELECT COUNT(x) FROM bucket WHERE type = 'z' AND district = 'Maboro';
$totalCountOfMaboro = $totalDistrictInX + $totalDistrictInY + $totalDistrictInZ;
I cannot use a JOIN query because the Couchbase server currently in use is below 5.50 which only supports joining documents between document key to document field and not between document fields.
Is there a way to achieve this with one just n1ql query? Any help will be much appreciated, please.
Use aggregate query without group by for total count, control what documents to count through predicate.
SELECT COUNT(1) AS cnt
FROM bucket
WHERE type IN ['x', 'y', 'z'] AND district = 'Maboro';
If you need count for each type use GROUP BY
SELECT type, COUNT(1) AS cnt
FROM bucket
WHERE type IN ['x', 'y', 'z'] AND district = 'Maboro'
GROUP BY type;
If you want total count and individual type, its counts as array
SELECT ARRAY_SUM(av[*].cnt) AS totalcnt, av AS details
LET av = (SELECT type, COUNT(1) AS cnt
FROM bucket
WHERE type IN ['x', 'y', 'z'] AND district = 'Maboro'
GROUP BY type);
Could a GROUP BY and COUNT combo be your solution?
SELECT COUNT(x) FROM bucket WHERE district = 'Maboro' GROUP BY type
Documentation

Query on jsonb array

I have this kind of json array and i want to check stringValue inside value array is null or not plus i want to check it with its id and fielddata is column name
[
{
"name": "50a5613e97e04cb5b8d32afa8a9975d1",
"value": {
"stringValue": null
}
},
{
"name": "bb127e8284c84692aa217539c4312394",
"value": {
"dateValue": 1549065600
}
}
]
query is:
select *
from field
WHERE (fielddata->>'name') = '50a5613e97e04cb5b8d32afa8a9975d1'
AND fielddata->'value'->>'stringValue' IS NOT NULL;
and I want use this query in laravel5.7
Try this
$result = \DB::table('field')->where('name', "50a5613e97e04cb5b8d32afa8a9975d1" )->where('value', $stringValue)->get();
if(isset($result)){
foreach($result as $res){
if(isset($res['value']->stringValue)){
// not null case
}else{
// null case
}
}
}
Within a SQL query, I think you want something like this:
select t.*
from the_table t
where exists (select *
from jsonb_array_elements(t.fielddata) as j(e)
where e ->> 'name' = '50a5613e97e04cb5b8d32afa8a9975d1'
and e -> 'value' ->> 'stringValue' is not null);
The exists sub-query will check every array element and see if at least one element has the specified name and a non-null stringValue. The query will then return the complete row from the table that fulfills the condition.
Online example: https://rextester.com/AGGJNR88809