How to write a seek/keyset pagination query using sequelize for postgres dialect? - postgresql

I have a raw SQL query written in pg-promise that looks as shown below
SELECT
f.feed_item_id,
pubdate,
link,
guid,
title,
summary,
author,
feed_id,
COALESCE(likes, 0) AS likes,
COALESCE(dislikes, 0) AS dislikes,
COALESCE(bullish, 0) AS bullish,
COALESCE(bearish, 0) AS bearish,
tags
FROM
feed_items f
LEFT JOIN
feed_item_likes_dislikes_aggregate l
ON f.feed_item_id = l.feed_item_id
LEFT JOIN
feed_item_bullish_bearish_aggregate b
ON f.feed_item_id = b.feed_item_id
WHERE
(
pubdate,
f.feed_item_id
)
< ($1, $2)
ORDER BY
pubdate DESC,
f.feed_item_id DESC LIMIT $3
How can I rewrite this query using sequelize?
My current attempt comes like this
FeedItem.findAll({
attributes: [
'feedItemId',
'pubdate',
'link',
'guid',
'title',
'summary',
'author',
'feedId',
'tags',
[sequelize.fn('COALESCE', sequelize.col('bullish'), 0), 'bullish'],
[sequelize.fn('COALESCE', sequelize.col('bearish'), 0), 'bearish'],
[sequelize.fn('COALESCE', sequelize.col('likes'), 0), 'likes'],
[sequelize.fn('COALESCE', sequelize.col('dislikes'), 0), 'dislikes'],
],
include: [{
model: FeedItemBullishBearishAggregate,
attributes: [],
}, {
model: FeedItemLikesDislikesAggregate,
attributes: [],
}],
order: [
['pubdate', 'DESC'],
['feedItemId', 'DESC']
],
limit: 1
}).then(a).catch(b)
How do I put that where condition in the above findAll expression?

Related

LEFT JOIN on table returns array with one element instead of empty array, when using json_build_object

I have the following query:
SELECT
u.*,
array_agg(
json_build_object(
'id', usn.id,
'schemaName', usn.schema_name
)
) AS schemas
FROM dev.users u
FULL OUTER JOIN dev.user_schema_names usn ON u.id = usn.user_id
WHERE u.email = $1
GROUP BY u.id
But for some odd reason, this returns the following:
{
id: 1,
email: 'test#test.com',
schemas: [ { id: null, schemaName: null } ]
}
The dev.user_schema_names has no records in it. I am expecting schemas to be an empty array []. If I insert records in dev.user_schema_names, then it works just fine, however.
What am I doing wrong? Should I be using something else instead of json_build_object?

CardinalityViolation when trying to use nested subqueries to retrieve JSON from Postgres using SQLAlchemy

I'm trying to translate the following Postgres query into Sqlalchemy 1.4:
SELECT json_build_object(
'type', 'FeatureCollection',
'features', json_agg(
json_build_object(
'type', 'Feature',
'geometry', geom,
'properties', (
select json_build_object(
'id', hi.id,
'responses', (
select json_object_agg(e.etype, er.response)
from expert e
inner join expertresponse er on e.id = er.expert_id
where infra_id = hi.id
),
'protections', (
select json_object_agg(p.ptype, i.pscore)
from protection p
inner join infraprotection i on p.id = i.protection_id
where infra_id = hi.id
)
)
)
)
)
) as allinfra
from hardinfra hi;
So I define the subqueries in the same order:
responses = (
db.session.query(
(func.json_object_agg(Expert.etype, Expert_Response.response)).label(
"responses"
)
)
.join(Expert_Response.exp)
.filter(Expert_Response.infra_id == Hardinfra.id)
.scalar_subquery()
)
protections = (
db.session.query(
(func.json_object_agg(Protection.ptype, Infra_Protection.pscore)).label(
"protections"
)
)
.join(Infra_Protection.prot)
.filter(Infra_Protection.infra_id == Hardinfra.id)
.scalar_subquery()
)
properties = db.session.query(
(
func.json_build_object(
"id", Hardinfra.id, "protections", protections, "responses", responses
).label("properties")
)
).scalar_subquery()
features = db.session.query(
(
func.json_build_object(
"type",
"Feature",
"geometry",
Hardinfra.geom,
"properties",
properties,
).label("features")
)
).scalar_subquery()
q = db.session.query(
func.json_build_object(
"type", "FeatureCollection", "features", func.json_agg(features)
)
)
However I get a (psycopg2.errors.CardinalityViolation) more than one row returned by a subquery used as an expression error when features is evaluated. I'm not even sure that properties and features need to be scalar subqueries (responses and protections certainly do), but I'm clearly also doing something else wrong, perhaps to do with correlating the inner Hardinfra refs to the outer ref? I'm not sureā€¦
It might be caused by redundant subqueries, you could try to remove the last two subqueries.
responses = (
db.session.query(
(func.json_object_agg(Expert.etype, Expert_Response.response)).label(
"responses"
)
)
.join(Expert_Response.exp)
.filter(Expert_Response.infra_id == Hardinfra.id)
.scalar_subquery()
)
protections = (
db.session.query(
(func.json_object_agg(Protection.ptype, Infra_Protection.pscore)).label(
"protections"
)
)
.join(Infra_Protection.prot)
.filter(Infra_Protection.infra_id == Hardinfra.id)
.scalar_subquery()
)
properties = func.json_build_object(
"id", Hardinfra.id, "protections", protections, "responses", responses
)
features = func.json_build_object(
"type",
"Feature",
"geometry",
Hardinfra.geom,
"properties",
properties,
)
q = db.session.query(
func.json_build_object(
"type", "FeatureCollection", "features", func.json_agg(features)
)
)

How to count json nodes in postgres jsonb

In my Postgres database I have a column jsonb with a order items:
[
{"discount": 29.96, "quantity": 1, "item_value": 69.94, "unit_price": 99.9, "stock_sku_id": 98906, "product_sku_id": 98775},
{"discount": 52.81, "quantity": 1, "item_value": 123.19, "unit_price": 176.0, "stock_sku_id": 15183, "product_sku_id": 15077}
]
I need count number of lines in this order.
I tried to use:
select (o.data->'items') from orders o where o.id = 34505
select count((o.data->'items')) from orders o where o.id = 34505
select (o.data->'items').count() from orders o where o.id = 34505
But any solution works.
I solve using JSONB_ARRAY_LENGTH function!

org.postgresql.util.PSQLException: ERROR: set-returning functions are not allowed in WHERE

I need a help for the below mentioned detail,
I am using Postgres + Spring-Data-JPA. Moreover, I have used the jsonb data type for storing data.
I am trying to execute a query, but it gives me the following error:
ERROR: set-returning functions are not allowed in WHERE
The cause here is that I have added a jsonb condition in the WHERE clause (kindly refer to the below query for more detail).
Query (I have renamed column name just because of hiding the actual column name):
select distinct
jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'firstName' as firstName,
jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'lastName' as lastName,
jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'country' as country
from
tale1 table10_
left outer join
table2 table21_
on table10_.end_user_id=table21_.end_user_id
left outer join
table3 table32_
on table10_.manufacturer_id=table32_.manufacturer_id
where
table21_.end_user_uuid=(
?
)
and table21_.is_active=true
and table32_.manufacturer_uuid=(
?
)
and table32_.is_active=true
and table10_.is_active=true
and table32_.is_active=true
and jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'action' = ('PENDING')
order by
jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'firstName',
jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'lastName'
limit ?
The following line in the above query is causing the error:
and jsonb_array_elements(initiated_referral_detail->'listOfAttribue')::jsonb
->> 'action' = ('PENDING')
Can anyone please guide me about how do fetch data from the inner JSON? Especially in my case I have an inner List and a few elements inside.
I recommend a lateral join with jsonb_array_elements for cases like that. Here is an example:
CREATE TABLE tale1 (
id integer PRIMARY KEY,
initiated_referral_detail jsonb NOT NULL
);
INSERT INTO tale1 VALUES
(1, '{
"name": "one",
"listOfAttribue": [
{ "id": 1, "action": "DONE"},
{ "id": 2, "action": "PENDING" },
{ "id": 3, "action": "ACTIVE" }
]
}');
INSERT INTO tale1 VALUES
(2, '{
"name": "two",
"listOfAttribue": [
{ "id": 1, "action": "DONE"},
{ "id": 2, "action": "ACTIVE" }
]
}');
To find all ids where the associated JSON contains an array element with action = PENDING, you can query like this:
SELECT DISTINCT id
FROM tale1 CROSS JOIN LATERAL
jsonb_array_elements(initiated_referral_detail -> 'listOfAttribue') AS attr
WHERE attr ->> 'action' = 'PENDING';

Sequelize order by two nested associations

I try to use the order for both my sub-queries. But sequelize generate a bad query and use this order by on main-query.
Here is my query:
Model.findAll({
order: sequelize.literal('("asset->forOrder"."value" - "asset.currenthours") desc),
offset: 0,
limit: 10,
include: [{
model: Asset,
as: 'asset',
include: [{
model: ThresholdService,
required: false,
as: 'thresholdservices'
}, {
model: ThresholdService,
where: {property: 'hours'},
required: false,
duplicating: false,
as: 'forOrder'
}],
}]
})
I expected to get query like this:
SELECT ..., "asset->forOrder"."asset_id", "asset->forOrder"."value"
FROM (
SELECT ...
FROM "machineidentity" AS "machineidentity"
LIMIT 10 OFFSET 0
) AS "machineidentity"
LEFT OUTER JOIN "asset" AS "asset" ON "machineidentity"."unique_id" = "asset"."machineIdentityId"
LEFT OUTER JOIN "thresholdservice" AS "asset->thresholdservices" ON "asset"."id" = "asset->thresholdservices"."asset_id"
LEFT OUTER JOIN "thresholdservice" AS "asset->forOrder" ON "asset"."id" = "asset->forOrder"."asset_id" AND "asset->forOrder"."property" = 'hours'
ORDER BY ("asset->forOrder"."value" - "asset"."currenthours") DESC;
but have:
SELECT ..., "asset->forOrder"."asset_id", "asset->forOrder"."value"
FROM (
SELECT ...
FROM "machineidentity" AS "machineidentity"
ORDER BY ("asset->forOrder"."value" - "asset"."currenthours") DESC
LIMIT 10 OFFSET 0
) AS "machineidentity"
LEFT OUTER JOIN "asset" AS "asset" ON "machineidentity"."unique_id" = "asset"."machineIdentityId"
LEFT OUTER JOIN "thresholdservice" AS "asset->thresholdservices" ON "asset"."id" = "asset->thresholdservices"."asset_id"
LEFT OUTER JOIN "thresholdservice" AS "asset->forOrder" ON "asset"."id" = "asset->forOrder"."asset_id" AND "asset->forOrder"."property" = 'hours'
ORDER BY ("asset->forOrder"."value" - "asset"."currenthours") DESC;
ORDER BY appear in machineidentity query.
I found in sequelize such code:
if (
subQuery
&& Array.isArray(order)
&& order[0]
&& !(order[0] instanceof Association)
&& !(typeof order[0] === 'function' && order[0].prototype instanceof Model)
&& !(typeof order[0].model === 'function' && order[0].model.prototype instanceof Model)
&& !(typeof order[0] === 'string' && model && model.associations !== undefined && model.associations[order[0]])
) {
subQueryOrder.push(this.quote(order, model, '->'));
}
mainQueryOrder.push(this.quote(order, model, '->'));
I have just created order, which not satisfied this if.
So, right now my order, looks like:
[['asset.forOrder', 'value', sequelize.literal('-(machine.asset.currentkilometers - machine.asset.initialvalueinkm)')]]