Sequelize js add total count of associated models - node.js

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.

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
});

Adding order clause in queries with nested association in Sequelize

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,
},
],
},
],

How to get Sequelize results WHERE MAX timestamps_of_multiple_nested_objects are greater than a certain date?

I have one main object that I need query results for, based on the timestamps of multiple HasMany note objects related to the main table. There are up to 3 different types of note objects that can be attached to one main object.
With Sequelize, I need to find the max timestamp for each note, then return a member if all of those timestamps are greater than x days old.
Both attempts below seem like they should work. This first tells me I'm using MAX wrong:
main_object.findAll({
include: [
{
model: this.database.note_type1,
as: 'note_type1',
required: false,
},
{
model: this.database.note_type2,
as: 'note_type2',
required: false,
},
],
where: {
[Sequelize.Op.or]: [
Sequelize.where([Sequelize.fn('max', Sequelize.col('note_type1.updated_at')), 'max_updated_at']),
{
'max_updated_at': {
[Sequelize.Op.lt]: max_date,
},
},
Sequelize.where([Sequelize.fn('max', Sequelize.col('note_type2.updated_at')), 'max_updated_at']),
{
'max_updated_at': {
[Sequelize.Op.lt]: max_date,
},
},
],
},
});
I've also tried ordering the includes by timestamp and limiting to 1, which says "column updated_at doesn't exist":
main_object.findAll({
include: [
{
model: this.database.note_type1,
as: 'note_type1',
required: false,
order: [
['updated_at', 'DESC'],
],
limit: 1,
},
{
model: this.database.note_type2,
as: 'note_type2',
required: false,
order: [
['updated_at', 'DESC'],
],
limit: 1,
},
],
where: {
[Sequelize.Op.or]: [
{
'$note_type1.updated_at$': { [Sequelize.Op.lt]: max_date },
},
{
'$note_type2.created_at$': { [Sequelize.Op.lt]: max_date },
},
],
},
)};
With this last solution, I understand Sequelize may not allow ordering this way - however, the one solution I've found does not let me limit or max, it simply orders.

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);
}

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',.

Resources