Adding order clause in queries with nested association in Sequelize - node.js

I trying to fetch the assessment details for a class in which assessment_test model has association with student_assessment_test model(hasMany). I want the fetched result ordered according to the marks obtained by student. I am trying the below method but it doesn't seem to be working. Please let me know the correct method for such queries.
const assessmentDetails = await Entity.assessmentTest.findOne({
where: { id: assessmentId, status: 1 },
attributes: [
'id',
'sectionId',
'assessmentDate',
'assessmentTitle',
'totalPoints',
],
include: [
{
association: 'assessmentTestDetails',
where: { status: 1 },
attributes: ['marksObtained', 'percentage', 'testStatus'],
required: true,
order: [['marksObtained', 'ASC']],
include: [
{
association: 'student',
where: { status: 1 },
attributes: ['studentName'],
required: true,
},
],
},
],

Related

Sequelize: order-by doesn't seem to work on aggregated output while using multiple joins

I've been trying to order the results by total no. of all reviews given for a particular seller's store.
All associations are defined but when I tried order by on avg(ratings) or count(id) [here id is id of alias named 'seller_details'], it gives me an error. I have tried many ways like using Sequelize.col() and giving all models names; using Sequelize.literal() but none works.
const data = await UserFavoriteStores.findAndCountAll({
where: {
customer_id: userId
},
include: [
{
model: SellerStoreDetail,
required: false,
include: [
{
model: StoreReviews,
required: false,
attributes: [],
as: 'seller_details'
}
],
attributes: {
include: [
[
Sequelize.fn(
'count',
Sequelize.col('favStoreData.seller_details.id')
),
'totalReviewCount'
],
[
Sequelize.fn(
'AVG',
Sequelize.col('favStoreData.seller_details.rating')
),
'avgRating'
]
]
},
as: 'favStoreData'
}
],
group: ['user_favorite_stores.id', 'favStoreData.id'],
limit: limit,
offset: skip,
subQuery: false
});

Group By with Sequelize

I have the following class structure:
I'm trying to group and count by Sequelize how many titles each selection had from the Cup_Selections table equal to the query typed below:
My Node query with Sequelize is as follows:
async index(req, res) {
const champions = await Champion.findAll({
attributes: ['id', 'cupselection_id'],
include: [
{
group: ['selection_id', 'champion.id'],
raw: true,
model: CupSelection,
as: 'cupselection',
attributes: [
'id',
'cup_id',
[fn('count', col('selection_id')), 'vezes'],
],
include: [
{
model: Selection,
as: 'selection',
attributes: ['id', 'country'],
},
],
},
],
});
return res.json(champions);
}
But the following error is displayed to me:
(node:28230) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: column "Champion.id" must appear in the GROUP BY clause or be used in an aggregate function
How can I solve ?
I solved it as follows:
async index(req, res) {
const { page = 1 } = req.query;
const champions = await Champion.findAll({
limit: 5,
offset: (page - 1) * 5,
order: [[fn('count', col('cupselection.selection.id')), 'DESC']],
attributes: [[fn('count', col('cupselection.selection.id')), 'vezes']],
group: ['cupselection.selection.id', 'cupselection.selection.logo.id'],
raw: true,
include: [
{
model: CupSelection,
as: 'cupselection',
attributes: [],
include: [
{
model: Selection,
as: 'selection',
attributes: ['id', 'country'],
include: [
{
model: File,
as: 'logo',
attributes: ['id', 'path', 'url'],
},
],
},
],
},
],
});
return res.json(champions);
}

sequelize: Not include model if where conditon of included model matches

I want to get all RecurringEvents that have no excludeDates for today.
I have following models:
Recurring events
const RecurringEvent = sequelize.definge('recurringEvent,{
id: {type: Sequelize.INTEGER, primaryKey:true},
title: Sequelize.STRING
});
And ExcludeDates with a foreign key recurringEventId
const ExcludeDate = sequelize.define('exclude_date',{
id: {type: Sequelize.INTEGER, primaryKey:true},
recurringEventId: Sequelize.INTEGER,
date: Sequelize.DATE
});
As a relationship i defined
RecurringEvent.hasMany(ExcludeDate, {foreignKey: 'recurringEventId'});
I can get all my RecurringEvents including the the excludeDates with
RecurringEvent.findAll({include:[{model:ExcludeDate}]});
That will give me an output like:
[
{
"id": 1,
"title": "Event1",
"exclude_dates": [
{
"id": 1,
"date": "2019-02-13",
"recurringEventId": 1,
},
{
"id": 2,
"date": "2019-02-14",
"recurringEventId": 1,
}
]
Now i would like to get the Recurring events but only if there is no exclude date for today.
so far i have tried
RecurringEvent.findAll({
include: [{
model: ExcludeDate,
where: {
date: {
[Op.ne]: moment().format('YYYY-MM-DD')
}
}
}]
})
But that only leaves out the ExcludeDate entry with the current Date like that :
[
{
"id": 1,
"title": "Event1",
"exclude_dates": [
{
"id": 2,
"date": "2019-02-14",
"recurringEventId": 1,
}
]
How can i exclude the whole RecurringEvent if and ExcludeDate for it is set for today?
Edit:
I also read in the docs
To move the where conditions from an included model from the ON condition to the top level WHERE you can use the '$nested.column$'
So i have tried this:
RecurringEvent.findAll({where:{
'$exclude_dates.date$':{
[Op.ne]: moment().format('YYYY-MM-DD')
}
},
include: [{model: ExcludeDate}]
})
But without any luck, i'm still getting RecurringEvents just without the one exclude date in the exclude_dates property
Try to add required: true, to your include model to make inner join instead of left join. e.g.
RecurringEvent.findAll({
include: [{
model: ExcludeDate,
required: true,
where: {
date: {
[Op.ne]: moment().format('YYYY-MM-DD')
}
}
}]
})

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 js add total count of associated models

I am trying to modify a query so it also returns a count of elements
I want to count the number of "PublicationComments" which relates to a "Publication". Right now the query looks like this:
let query = {
attributes: {
exclude: attributesToExclude,
},
where: {
'club_id': this.id,
},
order: [['date', 'DESC']],
include: [
{
model: models.PublicationComment,
association: models.Publication.hasMany(models.PublicationComment, { as: 'lastComments' }),
order: [['date', 'DESC']],
limit: 3,
include: [
{
model: models.User, as: 'user',
attributes: {
exclude: attributesToExclude,
},
}
],
},
{
model: models.PublicationLike,
association: models.Publication.hasMany(models.PublicationLike, { as: 'likes' }),
attributes: ['userId']
}
]
};
The result I am trying to obtain would look like this:
[ { id: '2',
clubId: '26',
teamId: null,
userId: '67',
date: '2017-04-18T11:23:05.628Z',
card:
{ type: 'status',
text: 'publication example text',
video: [Object] },
created_at: '2017-04-18T11:23:05.629Z',
updated_at: '2017-04-18T11:23:05.629Z',
deleted_at: null,
likes: [],
commentsCount: 4,
lastComments: [ [Object], [Object], [Object] ] }]
Note that there is a CommentCount property with the result of the wished count query
I tried doing add on include attributes the function of count by comments and repeat the association with PublicationComment model without limit parameter (I need the total).
Something like this:
attributes: {
include: [[sequelize.fn('count', sequelize.col(allComments.id), 'commentsCount']]
exclude: attributesToExclude,
},
And add the new associaton inside icludde array:
{
model: models.PublicationComment,
association: models.Publication.hasMany(models.PublicationComment, { as: 'allComments' })
}
but after two days of efforts wasted in this I am unable to make it work.
Has anyone any advise, resource or clarification that I could use to advance in this? Thanks.

Resources