issue in specifying attribute name while eagerLoading in Sequelize - node.js

I have a model and doing eager Loading in using findAll().
The issue is when I use sequelize.col("ColName"), it only works in first level of include.
But it gives an error ERROR Invalid column name 'exerciseLocation.name when I use it in the depper level JOIN (I've already added alias in the associations)
sequelize version : 6.14.1
Here is my code
Scheduler.findAll({
where: { userId: _userId },
attributes: [
"id",
"title",
[db.sequelize.col("Location.name"), "location"], // This works fine
],
include: [
{
model: Locations,
attributes: [],
},
{
model: ExerciseList,
attributes: [
"id",
"title",
[db.sequelize.col("exerciseLocation.name"), "location"], /* ERROR Invalid column name 'exerciseLocation.name'*/
],
include: [
{
model: Locations,
attributes: [],
},
],
},
],
})
My associations
db.Scheduler.belongsTo(db.Locations, {foreignKey: "location",});
db.Scheduler.hasMany(db.ExerciseList, {foreignKey: "SchedulerId",});
db.ExerciseList.belongsTo(db.Scheduler, {foreignKey: "SchedulerId",});
db.ExerciseList.belongsTo(db.Exercises, {foreignKey: "exerciseId",});
db.ExerciseList.belongsTo(db.Locations, {foreignKey: "locationId", as: 'exerciseLocation'});

Related

How to solve "Not unique table/alias"? (node, sequelize)

I am implementing a comment service using 'express' and 'sequelize' modules. This comment service supports 'reply'. The model has 'user' and 'comment'.
Comment.hasMany(Comment, {foreignKey: {name: 'parent_comment', allowNull: true}, as: 'reply'});
Comment.belongsTo(Comment, {foreignKey: {name: 'parent_comment', allowNull: true}, as: 'parent'});
User.hasMany(Comment, {foreignKey: {allowNull: false}, onDelete: 'CASCADE'});
Comment.belongsTo(User, {foreignKey: {allowNull: false}, onDelete: 'CASCADE'});
I want to join the user by bringing in the "reply" part of the comment. like below...
[
{
somedata...,
writer: { // User model
userdata....
},
reply: [
{
somedata....
writer: { // User model
userdata....
}
},
....
]
},
....
]
However, as a result, an error occurs while outputting a message of 'Not unique table/alias'. Erase the marked 'this line' part and bring it normally, but it's not the desired result. code like this,
const c = await Comment.findAll({
include: [
{
model: User
},
{
model: Comment,
include: [{ model: User}] //// this line!
},
]
});
How can I get the results I want? Thank you.
Because Comment has 2 relationships with Comment (of course with aliases) you always need to indicate a desired alias in queries when you need to include Comment in Comment:
const c = await Comment.findAll({
include: [
{
model: User
},
{
model: Comment,
as: 'reply', // or as: 'parent' depending on your goal
include: [{ model: User}]
},
]
});

How do I group by a column in a nested association in sequelize.js?

I'm trying to implement the following SQL query using sequelize.js:
select
practtype.description,
SUM("chargevalue") as "categoryvalue"
from
"public"."profees" as "profees"
inner join "public"."practitioners" AS "practitioner" on
"profees"."practitionerid" = "practitioner"."practitionerid"
inner join public.practtypes as "practtype" on
"practitioner"."practtypeid" = "practtype"."practtypeid"
group by
practtype.description
order by
practtype.description;
I have the following associations set up in my init-models.js component:
profees.belongsTo(practitioners, { as: "practitioner", foreignKey: "practitionerid"});
practitioners.hasMany(profees, { as: "profees", foreignKey: "practitionerid"});
practitioners.belongsTo(practtypes, { as: "practtype", foreignKey: "practtypeid"});
practtypes.hasMany(practitioners, { as: "practitioners", foreignKey: "practtypeid"});
I'm struggling to find decent documentation or examples of how to specify the group clause of my sequelize query. Here's what I currently have:
const feesSummary = await profees.findAll({
attributes: [
[sequelize.fn("SUM", sequelize.col("chargevalue")), "categoryvalue"],
// ["chargevalue", "categoryvalue"],
],
include: [
{
model: practitioners,
as: "practitioner",
required: true,
attributes: ["surname"],
include: [
{
model: practtypes,
as: "practtype",
required: true,
attributes: ["description"],
},
],
},
],
group: [
[
{ model: practitioners, as: "practitioner" },
{ model: practtypes, as: "practtype" },
"description",
],
],
order: [
[
{ model: practitioners, as: "practitioner" },
{ model: practtypes, as: "practtype" },
"description",
"ASC",
],
],
// where: sequelize.where(sequelize.fn("date_part", ["year", sequelize.col("chargedate")]), year)
});
(I've commented out the where clause for the time being, as it's also giving me separate issues).
When I try to execute the sequelize query above, I get the following error:
Error: Unknown structure passed to order / group: { model: practitioners, as: 'practitioner' }
at PostgresQueryGenerator.quote (/home/developer/medexpenses/medexps-service/node_modules/sequelize/lib/dialects/abstract/query-generator.js:888:11)
at PostgresQueryGenerator.aliasGrouping (/home/developer/medexpenses/medexps-service/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1418:17)
at /home/developer/medexpenses/medexps-service/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1343:82
at Array.map (<anonymous>)
at PostgresQueryGenerator.selectQuery (/home/developer/medexpenses/medexps-service/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1343:68)
at PostgresQueryInterface.select (/home/developer/medexpenses/medexps-service/node_modules/sequelize/lib/dialects/abstract/query-interface.js:954:27)
at Function.findAll (/home/developer/medexpenses/medexps-service/node_modules/sequelize/lib/model.js:1753:47)
I'm using version 6.6.2 of sequelize.
Can anyone post an example of the correct way to formulate the group clause in the query above? The Sequelize documentation suggests that
The syntax for grouping and ordering are equal, except that grouping does not accept a direction as last argument of the array (there is no ASC, DESC, NULLS FIRST, etc).
which is why I formulated the group clause as I did, but I'm getting the error above nonetheless.

Sequelize Aliases

I am working with sequelize and i have a model with two foreign keys
app.schemas.messengers.belongsTo(app.schemas.users, {
foreignKey: 'id_user_to',
as: 'to'
});
app.schemas.messengers.belongsTo(app.schemas.users, {
foreignKey: 'id_user_from',
as: 'from'
});
and the result of the query must return all messages of this specific user
this is the code of the query
return Users.findAll({
attributes: ['uuid', 'id', 'profile_pic', 'firstname', 'lastname', 'online'],
where: whereUser,
include: [{
model: Messengers,
as: 'from',
// as: 'to',
where: whereMessenger,
$or: [{
id_user_to: user.id,
},
{
id_user_from: user.id
}
],
order: [
['createdAt', 'ASC'],
],
}]
})
but only returns the message of users who write me not the messages to the user i wrote.
its there any way so I can put two aliases on the as attribute of sequelize, or is there other way to do so?
You have to include twice, e.g.
...
include: [
{
model: Messengers,
as: 'from'
/* other stuff */
},
{
model: Messengers,
as: 'to'
/* other stuff */
}
],
...
Also, you may have trouble with your alias names, as 'to' and 'from' are reserved words. I recommend msgTo and msgFrom instead...

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.

Order by in nested eager loading in sequelize not working

i have four model Tehsil, Ilr, Patwar, and Villages.
and their association is
Tehsil -> 1:m -> Ilr -> 1:m -> Patwar -> 1:m -> Villages
i want to to apply order by on all four of my models.
Query:
var tehsilQuery = {
include: [{
model: Ilr,
as: 'GirdawariKanoongo',
include: [{
model: Patwar,
as: 'GirdawariPatwar',
include: [{
model: Villages,
as: 'GirdawariVillages',
}]
}]
}],
order: [
['tehsil_name', 'ASC'],
[ {model: Ilr, as: 'GirdawariKanoongo'}, 'kanoongo_name', 'ASC'],
[ {model: Patwar, as: 'GirdawariPatwar'}, 'patwar_area', 'ASC'],
[ {model: Villages, as: 'GirdawariVillages'}, 'village_name', 'ASC'],
]
};
return Tehsils.findAll(tehsilQuery);
[Error: 'girdawari_patwar' in order / group clause is not valid association]
order by is working if i remove Patwar and Villages(lat two model) from order.
Another working example with nested ordering:
order: [
[ { model: chapterModel, as: 'Chapters' }, 'createdAt', 'ASC'],
[ { model: chapterModel, as: 'Chapters' },
{ model: partModel, as: 'Parts' }, 'createdAt', 'ASC']
],
where part and chapter have M:1 relation.
Our scenario was with two nested include statements where the inner most nesting was not ordering correctly. By applying the ordering at the highest level of the findAll we were able to successfully return the ordered object.
model relationship as follows for our surveySet.findAll:
suveySet hasMany surveys
surveys belongsToMany questions
order: [
[ { model: survey, as: 'survey' }, 'subjectId', 'ASC'],
[ { model: survey, as: 'survey' },
{ model: question, as: 'question' }, 'id', 'ASC']
]
i solved it.
here's how order looks:
order: [
'tehsil_name',
'GirdawariKanoongo.kanoongo_name',
'GirdawariKanoongo.GirdawariPatwar.patwar_area',
'GirdawariKanoongo.GirdawariPatwar.GirdawariVillages.village_name'
]
all i have to do is: using the as in association of table and chaining them followed by column_name on which order supposed to apply.
For anyone wondering how it could be achieved using object style definition, this is how it would be solved.
You could find more information about ordering in Sequelize documentation.
order: [
['tehsil_name', 'ASC'],
[ {model: Ilr, as: 'GirdawariKanoongo'}, 'kanoongo_name', 'ASC'],
[ {model: Ilr, as: 'GirdawariKanoongo'}, {model: Patwar, as: 'GirdawariPatwar'}, 'patwar_area', 'ASC'],
[ {model: Ilr, as: 'GirdawariKanoongo'}, {model: Patwar, as: 'GirdawariPatwar'}, {model: Villages, as: 'GirdawariVillages'}, 'village_name', 'ASC'],
]

Resources