Sequelize js not working as expected with Having and Group by - node.js

is there something wrong with my ORM query? I am trying to use sequelize group and having in order to filter Reservation dates that have more than 30 records:
SELECT "reservations"."reservationDate" FROM reservations, orders
WHERE "reservations"."orderId" = "orders"."orderId"
AND Orders.confirmed = true
GROUP BY "reservationDate"
HAVING COUNT("reservationDate") >= 30;
db.Reservations.findAll({
attributes: ['reservationDate'],
where: {
reservationDate: {
[Sequelize.Op.between]: [fistMonthDay, lastMonthDay],
},
},
include: [{
model: db.Orders,
attributes: [],
where: { confirmed: true }
}],
group: ['reservationDate'],
having: {
[Sequelize.fn("COUNT", Sequelize.col("reservationId"))]: {
[Sequelize.Op.gte]: 30,
}
}
})

Easy workaround:
having: Sequelize.literal(`count("reservation"."reservationId") >= 30`)

Related

Sequelize missing FROM-clause entry for table Postgres, after adding the limit and offset

i have a sequelize query like this. however, when I add limit and offset there is an error like this.
what should i do?
const courses = await DB_COURSES.findAll({
attributes: ["id"],
include:[
{
model: DB_COURSETRANSACTIONS,
attributes:["coursePurchasedId"],
include:[
{
model:DB_COURSES,
as: 'coursePurchased',
include:[
{
model: DB_COMPANIES,
as: 'buyerByCompany',
attributes:["id"]
}
],
required: true
}
],
required: true
},
{
model: DB_COMPANIES,
as: 'authorByCompany',
attributes: ["id"]
}
],
limit: 10,
offset: 0
})
error message
ERD table
I want like this:
like this

sequelize filtering for nested model

I've been working with sequelize in a couple of weeks, still trying to learn..
My Models are defined in models folder.
/models/endpoint.js
import Sequelize from 'sequelize';
import { sequelize } from '../data';
import Permission from './permission';
const { Model } = Sequelize;
class Endpoint extends Model { }
Endpoint.init({
endpoint: {
type: Sequelize.VIRTUAL(Sequelize.STRING, [ 'method', 'path' ]),
get() {
return `${this.get('method')} ${this.get('path')}`;
}
},
method: {
type: Sequelize.ENUM,
values: [ 'GET', 'POST', 'PUT', 'DELETE', 'PATCH' ],
allowNull: false
},
path: {
type: Sequelize.STRING,
allowNull: false
},
description: {
type: Sequelize.TEXT
}
}, {
sequelize,
modelName: 'endpoint'
});
Endpoint.Permissions = Endpoint.hasMany(Permission);
Permission.Endpoint = Permission.belongsTo(Endpoint, { as: 'permission' });
export default Endpoint;
/models/permission.js
import Sequelize from 'sequelize';
import { sequelize } from '../data';
const { Model } = Sequelize;
class Permission extends Model { }
Permission.init({
entity: {
type: Sequelize.ENUM,
values: [ '*', 'user', 'extension', 'queue', 'group' ],
defaultValue: '*'
},
role: {
type: Sequelize.STRING,
defaultValue: '*'
}
}, {
sequelize,
modelName: 'permission'
});
export default Permission;
found something in docs: Top level where with eagerly loaded models
User.findAll({
where: {
'$Instruments.name$': { [Op.iLike]: '%ooth%' }
},
include: [{
model: Tool,
as: 'Instruments'
}]
})
as following that, I made this
Endpoint.findAndCountAll({
where: {
path: { [Symbol(iLike)]: '%user%' },
'$permissions.role$': { [Symbol(eq)]: 'admin' }
},
include: [
{ model: permission, as: 'permissions' }
],
order: [],
offset: 0,
limit: 20
})
my code throws this error:
SequelizeDatabaseError: missing FROM-clause entry for table
"permissions"
and generated SQL query:
SELECT "endpoint".*,
"permissions"."id" AS "permissions.id",
"permissions"."entity" AS "permissions.entity",
"permissions"."role" AS "permissions.role",
"permissions"."createdAt" AS "permissions.createdAt",
"permissions"."updatedAt" AS "permissions.updatedAt",
"permissions"."endpointId" AS "permissions.endpointId",
"permissions"."permissionId" AS "permissions.permissionId"
FROM (
SELECT "endpoint"."id",
"endpoint"."method",
"endpoint"."path",
"endpoint"."description",
"endpoint"."createdAt",
"endpoint"."updatedAt"
FROM "endpoints" AS "endpoint"
WHERE "endpoint"."path" ilike '%user%'
AND "permissions"."role" = 'admin' limit 20 offset 0) AS "endpoint"
LEFT OUTER JOIN "permissions" AS "permissions"
ON "endpoint"."id" = "permissions"."endpointId";
Don't try to use limit and offset with hasMany associations and with findAndCountAll.
If you have 2 permissions in each endpoint (for instance you have 10 endpoints and set LIMIT to 10) then you'll get first 5 endpoints because in SQL query endpoints will be multiplied with permissions.
If you still want to filter parent records (endpoints) by some conditions on child records then I suppose you need to use sequelize.literal for that purpose.
If you want to filter parent and child records separately (and still use LIMIT and OFFSET) just move the permissions condition clause to association's where clause and also set separate:true in an association include to make LIMIT and OFFSET work correctly (this will make sequelize to execute separate SQL query to get permissions for each endpoint. This latter case will look like this:
Endpoint.findAndCountAll({
where: {
path: { [Symbol(iLike)]: '%user%' }
},
include: [
{
model: permission,
as: 'permissions',
separate: true,
where: {
role: { [Symbol(eq)]: 'admin' }
}
}
],
order: [],
offset: 0,
limit: 20
})

How to convert postgreSQL to Sequelize format

I have to try to convert my postgre sql query to orm concept using sequelize npm package, kindly guide me.
select * from "locationDepartmentMappings" as a
inner join "departments" as b on a."departmentId" = b.id
inner join "locations" as c on a."locationId" = c.id
where (
b."departmentName" like '%Accounting%' or c."locationName" like '%Accounting%'
)
limit 1;
As per below code still i have getting
error: column locationDepartmentMapping.department.departmentName does not exist
As #shivam mentioned i have tried depends mine below, can you what i need to changes,
let ldv = await LocationDepartmentModel.findAll({
include: [
{
model: LocationModel,
as: "location",
required: true,
},
{
model: DepartmentModel,
as: "department",
required: true,
}
],
where: {
$or: [
{
"department.departmentName": { like: `%${reqQueryName}%` }
},
{ "location.locationName": { like: `%${reqQueryName}%` } }
]
},
limit:1
});
Sequelize has pretty good documentation on how to write queries using the orm syntax.
To start with, the above query would look something like
Model.locationDepartmentMappings.findAll({
include: [
{
model: Model.departments
where: {departmentName: {$like: '% Accounting%'}}
},
{
model: Model.locations
where: {locationName: {$like: '% Accounting%'}}
}],
limit: 1
})
What you should consider getting to above query is
1. Learn how to create sequelize models
2. Learn Associations
3. Querying
There are a lot of great tutorials out there, which can help you get started, and are just a google search away!
Final with help got the solutions :
let ldData = await LocationDepartmentModel.findAll({
include: [
{
model: LocationModel,
as: "location",
required: true
},
{
model: DepartmentModel,
as: "department",
required: true
}
],
where: {
$or: [
{ "$department.departmentName$": { like: `%${reqQueryName}%` } },
{ "$location.locationName$": { like: `%${reqQueryName}%` } }
]
},
limit: 1
});
Courtesy for below :
#shivam answer for joining tables
#ManjulSigdel answer for where condition include table column

unknown column in field list sequelize

I'm trying to perform the following query using Sequelize:
db.Post.findAll({
include: [
{
model: db.User,
as: 'Boosters',
where: {id: {[Op.in]: a_set_of_ids }}
},
{
model: db.Assessment,
as: 'PostAssessments',
where: {UserId: {[Op.in]: another_set_of_ids}}
}
],
attributes: [[db.sequelize.fn('AVG', db.sequelize.col('Assessments.rating')), 'average']],
where: {
average: 1
},
group: ['id'],
limit: 20
})
But I run to this error: "ER_BAD_FIELD_ERROR". Unknown column 'Assessments.rating' in 'field list', although I do have table "Assessments" in the database and "rating" is a column in that table.
My Post model looks like this:
const Post = sequelize.define('Post', {
title: DataTypes.TEXT('long'),
description: DataTypes.TEXT('long'),
body: DataTypes.TEXT('long')
}, {
timestamps: false
});
Post.associate = function (models) {
models.Post.belongsToMany(models.User, {as: 'Boosters', through: 'UserPostBoosts' });
models.Post.hasMany(models.Assessment, {as: 'PostAssessments'});
};
What am I doing wrong?
It seems like this problem surfaces when we have a limit in a find query where associated models are included (the above error doesn't show up when we drop the limit from the query). To solve that, we can pass an option subQuery: false to the find. (https://github.com/sequelize/sequelize/issues/4146)
This is the correct query in case anyone comes across the same problem:
db.Post.findAll({
subQuery: false,
include: [
{
model: db.User,
as: 'Boosters',
where: {id: {[Op.in]: a_set_of_ids }}
}
,{
model: db.Assessment,
as: 'PostAssessments',
where: {UserId: {[Op.in]: another_set_of_ids}}
}
],
having: db.sequelize.where(db.sequelize.fn('AVG', db.sequelize.col('PostAssessments.rating')), {
[Op.eq]: 1,
}),
limit: 20,
offset: 2,
group: ['Post.id', 'Boosters.id', 'PostAssessments.id']
})
Error is with this one :
models.sequelize.col('Assessments.rating'))
Change it to
models.sequelize.col('PostAssessments.rating')) // or post_assessments.rating
Reason : You are using the alias for include as: 'PostAssessments',.

Sequelize ORM include model only if active = true

how can I findAll orders with id: 1 and include items only if this item has active = true? Otherwise there will be empty array...
Order.findAll({
where: { id: 1 },
include: [
{ model: Item, where: sequelize.and({'active' : true }) }
]
}).then(function(order) {
callback(null, order);
});
This shows me only orders where are some items with active = true. I wanted to show all orders with id: 1 and items as a sub-array ...
From Sequelize Tutorial:
Adding a where clause to the include automatically makes it required
The solution is this:
Order.findAll({
where: { id: 1 },
include: [
{ model: Item,
where: sequelize.and({'active' : true }),
required: false
}
]
}).then(function(order) {
callback(null, order);
});

Resources