So, I have these documents:
[
{ defaultName: "product X", brand: { name: "brand 00", id: "brand00-00" }, externalSpec: "spec00" },
{ defaultName: "product Y", brand: null, externalSpec: "spec01" },
{ defaultName: "product LL", brand: { name: "brand 01", id: "brand00-01" }, externalSpec: "spec00" },
{ defaultName: "product X", brand: { name: "brand 00", id: "brand00-00" }, externalSpec: "spec01" },
]
I'm using Group By with this query and it's working fine by a existing field on the documents:
SELECT ARRAY_AGG(p) FROM `BucketXXX` AS p
WHERE p.type = 'product'
AND p.deleted = false
GROUP BY p.defaultName
Now I would like to use my group by query but using a concatenated field on the select clause, I need this to check if the products are equal, something like:
SELECT p.defaultName || p.brand.id || p.externalSpec AS custom_key, ARRAY_AGG(p) FROM `BucketXXX` AS p
WHERE p.type = 'product'
AND p.deleted = false
GROUP BY custom_key
but no luck, currently getting error 3000 syntax error near AS, also keep in mind that brand could be null and I would like to add an empty string if that is null to continue with the externalSpec field,
Appreciate for the help,
Thanks
Projection Alias can be used in ORDER BY Only. Due to evaluation order (FROM, JOIN, LET, WHERE, GROUP BY, LETTING, PROJECTION, ORDER BY).
CB 6.5 or higher GROUP BY alias is supported
SELECT custom_key, ARRAY_AGG(p) FROM `BucketXXX` AS p
WHERE p.type = 'product'
AND p.deleted = false
GROUP BY p.defaultName || p.brand.id || p.externalSpec AS custom_key;
OR
SELECT custom_key, ARRAY_AGG(p) FROM `BucketXXX` AS p
LET custom_key = p.defaultName || p.brand.id || p.externalSpec
WHERE p.type = 'product'
AND p.deleted = false
GROUP BY custom_key;
You have null brand, If required use CONCAT(p.defaultName, IFMISSINGORNULL(p.brand.id,""), p.externalSpec)
Related
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;
I have two tables a coupons table and a coupon_city_map table.
id
coupon_code
1
OFFER20
2
OFFER10
3
OFFER50
4
OFFER40
5
OFFER90
coupon_Id
city_id
1
2
2
3
3
4
4
2
I need coupons with ids 1 4, and 5 for city_id = 2.
So It should fetch all the coupons where city_id=2 i.e. coupons with id 1 and 4
and it should also fetch coupons which don't have key in coupon_city_map i.e 5.
This is what I have tried but the query in [Op.or] is not working, and it returns all the coupons instead.
let coupons = await Coupon.findAll({
where: {
[Op.or]: [
{ '$CouponCities.city_id$': city_id },
{ '$CouponCities.coupon_id$': null },
],
...filters // other filter like is_active: true
},
include: {
model: CouponCity,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
The query being generated
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities` ON `Coupon`.`id` = `CouponCities`.`coupon_id`
WHERE (`Coupon`.`user_id` IS NULL OR `Coupon`.`user_id` = 1)
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false
AND `Coupon`.`start_date` < '2020-12-30 10:33:20'
AND `Coupon`.`expiry_date` > '2020-12-30 10:33:20';
Update
I also tried below, but still it is returning all the coupons.
let coupons = await Coupon.findAll({
// where: {
// ...filters,
// },
include: {
model: CouponCity,
required: false,
where: {
[Op.or]: [
{
zone_id: zoneId,
}, {
coupon_id: null,
},
],
},
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount','discount_upto', 'description', 'display'],
});
...and it generates below query.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_city_map` AS `CouponCities`
ON `Coupon`.`id` = `CouponCities`.`coupon_id`
AND ( `CouponCities`.`zone_id` = 1
AND `CouponCities`.`coupon_id` IS NULL )
WHERE `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
This is what worked for me, query is mess but it works. I am posting all the codes for better understanding for anyone interested.
Here zone is city.
{
const filters = {
start_date: {
[Op.lt]: new Date(),
},
expiry_date: {
[Op.gt]: new Date(),
},
};
if (userId) {
filters[Op.or] = [{
user_id: null,
}, {
user_id: userId,
}];
filters[Op.and] = {
[Op.or]: [
sequelize.literal('CouponZones.zone_id = 1'),
sequelize.literal('CouponZones.coupon_id IS null')
],
};
} else {
filters.user_id = null;
}
let coupons = await Coupon.findAll({
where: {
...filters,
},
include: {
model: CouponZone,
attributes: [],
},
attributes: ['id', 'coupon_code', 'discount_per', 'flat_discount', 'discount_upto', 'description', 'display'],
});
This is the query it generates.
SELECT `Coupon`.`id`,
`Coupon`.`coupon_code`,
`Coupon`.`discount_per`,
`Coupon`.`flat_discount`,
`Coupon`.`discount_upto`,
`Coupon`.`description`,
`Coupon`.`display`
FROM `coupons` AS `Coupon`
LEFT OUTER JOIN `coupon_zone_map` AS `CouponZones`
ON `Coupon`.`id` = `CouponZones`.`coupon_id`
WHERE ( `Coupon`.`user_id` IS NULL
OR `Coupon`.`user_id` = 1 )
AND ((CouponZones.zone_id = 1 OR CouponZones.coupon_id IS null))
AND `Coupon`.`is_active` = true
AND `Coupon`.`is_external` = false;
Use UNION
You can write query like below
SELECT coupons.*
FROM coupons,
coupon_city_map
WHERE coupons.id = coupon_city_map.coupon_id
AND coupon_city_map.city_id = 2
UNION
SELECT coupons.*
FROM coupons
WHERE coupons.id NOT IN(SELECT coupon_city_map.coupon_id
FROM coupon_city_map)
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";
In postgres Say I have schema as such:
table item {
type varchar(40)
entity_id bigint
entity_type varchar(40)
user_id bigint
}
And I want to query the table to get the info like this:
{
"typeA": {
"count": 3,
"me": true
},
"typeC": {
"count": 3,
"me": false
},
"typeE": {
"count": 3,
"me": false
},
"typeR": {
"count": 3,
"me": true
}
}
From a query where the main data is this:
SELECT ARRAY_AGG(x)
FROM
(
SELECT type,
count(*),
(CASE
WHEN (SELECT id
FROM items as i
WHERE i.entity_type = 'sometype'
AND i.entity_id = 234
AND i.user_id = 32
AND i.type = items.type) is not null
THEN true
ELSE false
END) AS me
FROM items
WHERE items.entity_type = 'sometype'
AND items.entity_id = 234
GROUP BY type
) as x
This returns an array of the info i need type count and me. But I need it formatted like above versus:
[
{
"type": "typeA",
"count": 3,
"me": true
},
{
"type": "typeC",
"count": 3,
"me": false
},
{
"type": "typeE",
"count": 3,
"me": false
},
{
"type": "typeR",
"count": 3,
"me": true
}
]
Which is the current way it is formatted. Have been unable to find a way to build the json object I need. I was able to get three json objects that are like that But I need the three nested in one object.
Not exactly what you want, but from PostgreSQL - Aggregate Functions, I would guess, you can try json_object_agg(name, value), e.g.
SELECT JSON_OBJECT_AGG(type, x)
FROM
(
SELECT type,
count(*),
(CASE
WHEN (SELECT id
FROM items as i
WHERE i.entity_type = 'sometype'
AND i.entity_id = 234
AND i.user_id = 32
AND i.type = items.type) is not null
THEN true
ELSE false
END) AS me
FROM items
WHERE items.entity_type = 'sometype'
AND items.entity_id = 234
GROUP BY type, me
) as x
I have a table defined like this:
CREATE TABLE data_table AS (
id bigserial,
"name" text NOT NULL,
"value" text NOT NULL,
CONSTRAINT data_table_pk PRIMARY KEY (id)
);
INSERT INTO data_table ("name", "value") VALUES
('key_1', 'value_1'),
('key_2', 'value_2');
I would like to get a JSON object from this table content, which will look like this:
{
"key_1":"value_1",
"key_2":"value_2"
}
Now I'm using the client application to parse the result set into JSON format. Is it possible to accomplish this by a postgresl query?
If you're on 9.4 you can do the following:
$ select json_object_agg("name", "value") from data_table;
json_object_agg
----------------------------------------------
{ "key_1" : "value_1", "key_2" : "value_2" }
select
format(
'{%s}',
string_agg(format(
'%s:%s',
to_json("name"),
to_json("value")
), ',')
)::json as json_object
from data_table;
json_object
---------------------------------------
{"key_1":"value_1","key_2":"value_2"}
In a generic scenario you can nest more than one json_object_agg functions on top of a subquery. The inner subqueries should always have at least one column that will be used by outer subquery as keys for the json_object_agg function.
In the example, in the subquery C the values of the column action are used as keys in the subquery A. In A the values of column role are used as keys in query A.
-- query A
select json_object_agg(q1.role, q1.actions) from (
-- subquery B
select q2.role, json_object_agg(q2.action, q2.permissions) as actions from (
-- subquery C
select r.name as role, a.name as action, json_build_object (
'enabled', coalesce(a.bit & bit_and(p.actionids) <> 0, false),
'guestUnsupported', r.name = 'guest' and a."guestUnsupported"
) as permissions
from role r
left join action a on a.entity = 'route'
left join permission p on p.roleid = r.id
and a.entity = p.entityname
and (p.entityid = 1 or p.entityid is null)
where
1 = 1
and r.enabled
and r.deleted is null
group by r.name, a.id
) as q2 group by q2.role
) as q1
The result is a single row/single column with the following content:
{
"Role 1": {
"APIPUT": {
"enabled": false,
"guestUnsupported": false
},
"APIDELETE": {
"enabled": false,
"guestUnsupported": false
},
"APIGET": {
"enabled": true,
"guestUnsupported": false
},
"APIPOST": {
"enabled": true,
"guestUnsupported": false
}
},
"Role 2": {
"APIPUT": {
"enabled": false,
"guestUnsupported": false
},
"APIDELETE": {
"enabled": false,
"guestUnsupported": false
},
"APIGET": {
"enabled": true,
"guestUnsupported": false
},
"APIPOST": {
"enabled": false,
"guestUnsupported": false
}
}
}