Why does sequelize add the COUNT of each model I include together? - javascript

I'm trying to get the information about a user and include all the reservation he has done as well as the total sales.
I'm trying to add a before get hook and include both reservations and sales. When I include just one of these it gets the COUNT right, but when I add both, it actually counts reservations and sales and adds them together for each one.
get: [
authenticate("jwt"),
context => {
context.params.sequelize = {
include: [
{
association: "reservacion",
required: false,
attributes: [[Sequelize.fn("COUNT", Sequelize.col("reservacion.id")), "total_res"]]
},
{
association: "venta",
required: false,
attributes: [[Sequelize.fn("COUNT", Sequelize.col("venta.id")), "ventas"]]
}
]
};
return context;
}
],

If you use DISTINCT you should avoid the problem of accumulation of results
get: [
authenticate("jwt"),
context => {
context.params.sequelize = {
include: [
{
association: "reservacion",
required: false,
attributes: [[Sequelize.fn("COUNT", Sequelize.fn("DISTINCT", Sequelize.col("reservacion.id")), "total_res"]]
},
{
association: "venta",
required: false,
attributes: [[Sequelize.fn("COUNT", Sequelize.fn("DISTINCT", Sequelize.col("venta.id"))), "ventas"]]
}
]
};
return context;
}
],

Related

Sequelize filtering one to many relation

I have a User model and Timeoffs model with one to many relation. I want get all the users that doesn't have timeoffs in the specified date. Right now in the code I'm doing the exact opposite of this - getting only the users with timeoffs in the given date. How can I do this in right way? Is it possible to just invert include in that part or should I write a more complex query?
getQuestionHourUsersByDate (date, timeId) {
return UsersModel.findAll({
where: {
[USERS.COLUMNS.QH_STATUS]: true,
},
include: [
{
model: TimeoffsModel,
where: {
[Operator.and]: {
[TIMEOFFS.COLUMNS.PROCEED_STATUS]: true,
[TIMEOFFS.COLUMNS.STATUS]: TimeOffEnums.TIMEOFF_REQUEST_STATUS.APPROVED,
},
[Operator.and]: {
[TIMEOFFS.COLUMNS.START_DATE]: {
[Operator.lte]: date,
},
[TIMEOFFS.COLUMNS.END_DATE]: {
[Operator.gte]: date,
},
},
},
},
{
model: RolesModel,
where: {
[ROLES.COLUMNS.ROLE_GROUP_ID]: 1,
},
through: {
attributes: [],
where: {
[USER_ROLES.COLUMNS.STATE]: true,
},
},
},
{
model: ResponsibilitiesModel,
attributes: [
RESPONSIBILITIES.COLUMNS.NAME,
RESPONSIBILITIES.COLUMNS.RESPONSIBILITY_GROUP_ID,
RESPONSIBILITIES.COLUMNS.COLOR_CODE,
],
where: {
[RESPONSIBILITIES.COLUMNS.RESPONSIBILITY_GROUP_ID]: 2,
},
required: false,
through: {
attributes: [],
where: {
[USER_RESPONSIBILITIES.COLUMNS.ACTIVE]: true,
},
},
},
{
model: LanguagesModel,
attributes: [
LANGUAGES.COLUMNS.CODE,
LANGUAGES.COLUMNS.NAME,
],
},
{
model: UserCalendarsModel,
include: [
{
model: CalendarsModel,
where: {
[CALENDARS.COLUMNS.START_DATE]: date,
[CALENDARS.COLUMNS.ACTIVE]: true,
},
include: [
{
model: QuestionHourSlotsModel,
where: {
[QUESTION_HOUR_SLOTS.COLUMNS.TIME_ID]: timeId,
},
},
],
},
],
},
],
});
}
Unfortunately, I should use Sequelize.literal in where option to add a subquery condition with NOT EXISTS like this:
where: Sequelize.where(Sequelize.literal('NOT EXISTS (SELECT 1 FROM ... WHERE startDate <= #date and endDate >= #date)'), '=', true)
and also to pass a specified date you add to indicate bind option along with main query options like this:
where: {
[USERS.COLUMNS.QH_STATUS]: true,
},
bind: {
date
}

Sequelize filter the included tables by where

I am trying to findAll records included nested tables, but did not understand how could I filter included tables by where clause. Here are the words:
const players = await PlayerService.findPlayers({
attributes: { exclude: ['password'] },
include: [
{ all: true },
{
model: Team,
as: 'captainTeams',
attributes: {exclude: ['createdAt', 'updatedAt']}
},
{
model: Team,
as: 'teams',
where: { type: 1 },
required: true,
through: {attributes: []},
attributes: {exclude: ['createdAt', 'updatedAt']}
}
]
})
Here is the result:
If I delete where and required from including Team clause, here is the result:
I would like to filter teams.type=2. Could you help me ?

Sequelize querying both parent model and included model using [Op.or]

I want to findAll Bookings where the booking has been paid.
A legacy booking has been paid if the paymentAuthorised: boolean attribute on the Booking table is true.
A new booking has been paid if the paymentAuthorised: boolean attribute on the Payment table is true and type: string attribute on the Payment table is 'booking'.
When I perform the following query it returns an error saying payments.paymentAuthorised not found.
const bookings = await db.Booking.findAll({
include: [
{
model: db.Payment,
as: "payments",
},
],
where: {
[Op.or]: [
{
paymentAuthorised: { [Op.eq]: true },
},
{
"$payments.paymentAuthorised$": { [Op.eq]: true },
"$payments.type$": { [Op.eq]: "booking" },
},
],
},
order: [["dateTime", "asc"]],
});
I worked this issue out in the end by logging the generated SQL. You need to add the following parameter: subQuery: false. This is so it generates an SQL query which includes the joins before the where.
const bookings = await db.Booking.findAll({
include: [
{
model: db.Payment,
as: "payments",
},
],
where: {
[Op.or]: [
{
paymentAuthorised: { [Op.eq]: true },
},
{
"$payments.paymentAuthorised$": { [Op.eq]: true },
"$payments.type$": { [Op.eq]: "booking" },
},
],
},
subQuery: false,
order: [["dateTime", "asc"]],
});

Sequelize query all associated items by another multiple associated items

my models looks like this:
user belongs to many categories
post belongs to many categories
through a joint tables of UserCategories and PostCategories
How do I select all posts which has the same categories as user ( for all categories which user is related ).
Get all categories for user.
const userCategory = await UserCategory.findAll({
where: {
userId: 1,
},
raw: true,
});
Get all posts for user categories.
const posts = await PostCategory.findAll({
include: [
{
model: Post,
required: true,
},
{
model: Category,
required: true,
include: {
model: UserCategory,
required: true,
include: {
model: User,
required: true,
where: {
id: userCategory.map(item => item.categoryId),
},
},
},
},
],
});

How to Avoid Sequelize JS Associations Including both the Foreign Key and the Included Object

How can I avoid showing both the foreignKey that sequelize creates and the eagerly fetched object through includes?
I have the following model structure:
FormEntry:
owner: User
createdBy: User
modifiedBy: User
formEntryData: [FormEntryData]
I modeled it after reading through SequelizeJS docs and came up with the following:
const User = sequelize.define('user', {
id: {
type: Sequelize.BIGINT(20),
field: 'user_id',
primaryKey: true
},
emailAddress: {
type: Sequelize.STRING(256),
field: 'email_address'
}
}, {
tableName: 'users',
timestamps: false
});
const FormEntryData = sequelize.define('formEntryData', {
id: {
type: Sequelize.BIGINT(20),
field: 'id',
primaryKey: true
},
entryId: {
type: Sequelize.BIGINT(20),
field: 'entry_id'
},
...
}, {
tableName: 'formEntryData',
timestamps: false
});
const FormEntry = sequelize.define('formEntry', {
id: {
type: Sequelize.BIGINT(20),
field: 'entry_id',
primaryKey: true
},
...
}, {
tableName: 'formEntries',
timestamps: false
});
I then need to create the associations to tie the models together and after a lot of trial and error I came up with the following:
FormEntry.hasMany(FormEntryData, {foreignKey: 'entry_id', as: 'FormEntryData'});
FormEntry.belongsTo(User, {foreignKey: 'created_by', as: 'CreatedBy'});
FormEntry.belongsTo(User, {foreignKey: 'modified_by', as: 'ModifiedBy'});
FormEntry.belongsTo(User, {foreignKey: 'owner', as: 'Owner'});
I then was able to query the data by doing the following:
FormEntry.findByPrimary(1472280, {
include: [
{
model: FormEntryData,
as: "FormEntryData"
},
{
model: User,
as: "CreatedBy"
},
{
model: User,
as: "Owner"
},
{
model: User,
as: "ModifiedBy"
}
]
})
Unfortunately, my results seem kind of repetitive as it seems to be including both the foreign key and the object that is eagerly fetched.
{
"id": 1472280,
...
"created_by": 26508, <-- repetitive (don't want this)
"modified_by": 26508, <-- repetitive (don't want this)
"owner": null, <-- repetitive (don't want this)
"FormEntryData": [
{
"id": 27164476,
"entryId": 1472280, <-- repetitive (but I want this one)
...
"entry_id": 1472280 <-- repetitive (don't want this)
},
...
],
"CreatedBy": { <-- repetitive (but I want this one)
"id": 26508,
"emailAddress": "swaraj.kler#greywallsoftware.com"
},
"Owner": null, <-- repetitive (but I want this one)
"ModifiedBy": { <-- repetitive (but I want this one)
"id": 26508,
"emailAddress": "swaraj.kler#greywallsoftware.com"
}
}
You need to exclude specified fields from the query
FormEntry.findByPrimary(1472280, {
include: [
{
model: FormEntryData,
as: "FormEntryData",
attributes: { exclude: ['entry_id'] }
},
{
model: User,
as: "CreatedBy"
},
{
model: User,
as: "Owner"
},
{
model: User,
as: "ModifiedBy"
}
],
attributes: { exclude: ['owner', 'created_by', 'modified_by'] }
})

Categories