Group By with Sequelize - node.js

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

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

Counting number of associated rows in sequelize

I am trying to find the count of students inside the classStudents association. Here teacher_details table is connected to class_details tables using 'section'
association and class_details tables is connected to student_details table using 'classStudents' association. I have tried the below method but got error ==>
Unknown column 'section->classStudents.studentId' in 'field list'
please let me know the correct procedure to count the associated students count
const getAssignedDetails = async (req, res) => {
try {
const assignedDetails = await Entity.teacherAssignedDetail.findAll({
where: { status: 1, teacherId: req.teacherId },
attributes: [
'role',
[
Sequelize.fn(
'COUNT',
Sequelize.col('section.classStudents.studentId')
),
'studentCount',
],
],
include: [
{
association: 'section',
attributes: ['sectionId', 'className', 'classEmoji'],
include: [
{
association: 'classStudents',
where: { status: 1 },
required: false,
},
],
where: { status: 1 },
},
{
association: 'subjectDetails',
attributes: [['id', 'masterSubjectId'], 'subjectName'],
},
],
});
res.json({
responseCode: 0,
responseMessage: 'Success',
responseData: assignedDetails,
});
} catch (err) {
res.status(500).send(errorHandling(err.message));
}
};

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

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 throws Error "Unable to find a valid association for model x" When Ordering By Associated Model

I have a problem with sequelize, when I want to ordering my query result by associated model, sequelize throw this error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Unable to find a valid association for model, 'productLanguage'
These are my files:
**Context.js **
const Sequelize = require('sequelize');
const sequelize = new Sequelize("postgres://postgres:123456#localhost:5432/sampleDB");
module.exports = {
Sequelize: Sequelize,
sequelize: sequelize
}
User.js
const context = require('../context');
module.exports = context.sequelize.define('user', {
name: context.Sequelize.STRING,
},{
freezeTableName: true
});
Product.js
const context = require('../context');
module.exports = context.sequelize.define('product', {
slug: context.Sequelize.STRING,
price: context.Sequelize.DECIMAL(10,2),
},{
freezeTableName: true
});
ProductLanguage.js
const context = require('../context');
module.exports = context.sequelize.define('productLanguage', {
name: context.Sequelize.STRING,
},{
freezeTableName: true,
timestamps: false
});
Language.js
const context = require('../context');
module.exports = context.sequelize.define('language', {
name: context.Sequelize.STRING,
slug: context.Sequelize.STRING,
},{
freezeTableName: true
});
db.js
var context = require('./context');
var User = require('./models/User'),
Product = require('./models/Product'),
ProductLanguage = require('./models/ProductLanguage'),
Language = require('./models/Language');
// ===================== ASSOCIATIONS =====================
// user 1:m Product
Product.belongsTo(User); // product owner
User.hasMany(Product);
// Product 1:m ProductLanguage m:1 Language
ProductLanguage.belongsTo(Product);
Product.hasMany(ProductLanguage);
ProductLanguage.belongsTo(Language);
Language.hasMany(ProductLanguage);
module.exports = {
Sequelize: context.Sequelize,
sequelize: context.sequelize,
models: {
Product: Product,
User: User,
ProductLanguage: ProductLanguage,
Language: Language
}
}
and finally this is my query
app.get('/', async (req, res, next)=>{
var result = await db.models.User.findAll({
include:[
{
model: db.models.Product,
attributes: ['price'],
include: [
{
model: db.models.ProductLanguage,
attributes: ['name'],
include: [
{
model: db.models.Language,
attributes: ['name'],
}
]
}
]
}
],
order:[
[db.models.ProductLanguage, 'name', 'desc']
],
attributes: ['name']
});
res.send(result);
});
The query work fine without "order" part, so I think the problem should be one on these :
Something is wrong on this part: [db.models.ProductLanguage, 'name', 'desc']
Something is wrong on association definitions
Note: I've searched on youtube and stackoverflow and sequelize documentation over 4 days but nothing found.
I use these dependencies:
"express": "^4.16.2",
"pg": "^6.4.2",
"pg-hstore": "^2.3.2",
"sequelize": "^4.32.2"
I've found the solution.
I must put all associated model into order, so the correct query is:
order:[
[db.models.Product, db.sequelize.models.ProductLanguage, 'name', 'desc']
],
The full query must be:
var result = await db.models.User.findAll({
include:[
{
model: db.models.Product,
attributes: ['price'],
include: [
{
model: db.models.ProductLanguage,
attributes: ['name'],
include: [
{
model: db.models.Language,
attributes: ['name'],
}
]
}
]
}
],
order:[
[db.models.Product, db.sequelize.models.ProductLanguage, 'name', 'desc']
],
attributes: ['name']
});
I hope this will be helpful for others.
Those who still won't get the result, try this syntax -
order:[[{ model: db.models.ProductLanguage, as: 'language_of_product' } , 'name', 'desc']]
In addition to Moradof's answer, it's important to note that if you specify an alias for your included model, then you must also specify the alias in the order statement.
Building on the previous example, we get:
var result = await db.models.User.findAll({
include:[
{
model: db.models.Product,
as: 'include1',
attributes: ['price'],
include: [
{
model: db.models.ProductLanguage,
as: 'include2',
attributes: ['name'],
include: [
{
model: db.models.Language,
attributes: ['name'],
}
]
}
]
}
],
order:[
[{ model: db.models.Product, as: 'include1' },
{ model: db.sequelize.models.ProductLanguage, as: 'include2' },
'name',
'desc']
],
attributes: ['name']
});
Note that because I named the Product as include1 in the include statement, I also had to name it as include1 in the order statement.
order:[
[{ model: db.models.Product, as: 'include1' },
{ model: db.sequelize.models.ProductLanguage, as: 'include2' },
'name',
'desc']
After using this sequlizer is creating this in query. ORDER BY ``.name DESC LIMIT 10;
So how can I pass the table alias before name.

Resources