Ordering results of eager-loaded nested models in Node Sequelize - node.js

I have a complex set of associated models. The models are associated using join tables, each with an attribute called 'order'. I need to be able to query the parent model 'Page' and include the associated models, and sort those associations by the field 'order'.
The following is having no effect on the results' sort order:
db.Page.findAll({
include: [{
model: db.Gallery,
order: ['order', 'DESC'],
include: [{
model: db.Artwork,
order: ['order', 'DESC']
}]
}],
})

I believe you can do:
db.Page.findAll({
include: [{
model: db.Gallery
include: [{
model: db.Artwork
}]
}],
order: [
// sort by the 'order' column in Gallery model, in descending order.
[ db.Gallery, 'order', 'DESC' ],
// then sort by the 'order' column in the nested Artwork model in a descending order.
// you need to specify the nested model's parent first.
// in this case, the parent model is Gallery, and the nested model is Artwork
[ db.Gallery, db.ArtWork, 'order', 'DESC' ]
]
})
There are also a bunch of different ways, or things you can do when ordering. Read more here: https://sequelize.org/master/manual/model-querying-basics.html#ordering-and-grouping

If you also use 'as' and let's say you want to order by 'createdDate' , the query looks like this:
DbCategoryModel.findAll({
include: [
{
model: DBSubcategory,
as: 'subcategory',
include: [
{
model: DBProduct,
as: 'product',
}
],
}
],
order: [
[
{model: DBSubcategory, as: 'subcategory'},
{model: DBProduct, as: 'product'},
'createdDate',
'DESC'
]
]
})

order: [
[ db.Sequelize.col('order'), 'DESC'], /*If you want to order by page module as well you can add this line*/
[ db.Gallery, db.ArtWork, 'order', 'DESC' ]
]

This works for me:
let getdata = await categories_recipes.findAll({
order:[
[{model: recipes, as: 'recipesdetails'},'id', 'DESC'] // change your column name like (id and created_at)
],
include:[{
model:recipes, as : "recipesdetails",
include:[{
model:recipe_images, as: "recipesimages",
}],
where:{
user_id:data.id
},
required: true,
}]
})

Just for completeness, another thing that also works is using sequelize.col as in:
db.Page.findAll({
include: [{
model: db.Gallery
include: [{
model: db.Artwork
}]
}],
order: [
[ sequelize.col('Gallery.order', 'DESC' ],
[ sequelize.col('Gallery.Artwork.order', 'DESC' ]
]
})
In this particular case it is slightly worse than the Arrays from https://stackoverflow.com/a/30017078/895245 (which more explicitly use existing Js classes rather than magic strings) but it seems that in most cases besides order:, .col is accepted but arrays aren't so it is good to have it in mind too.
There are some additional difficulties to overcome when you also need to limit: in nested includes:
how can i use limit in include model using sequelize
https://github.com/sequelize/sequelize/issues/8802
When limiting on toplevel only, it seems that subQuery: false is required e.g. as in:
u0WithComments = await User.findOne({
where: { id: u0.id },
order: [[
'Comments', 'body', 'DESC'
]],
limit: 1,
subQuery: false,
include: [{
model: Comment,
}],
})

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

fetching data using sequelize

i have player table has name and profileId
profile table has numberOfKills ,rankId and power
rank table has rankName
i want to get all players data from above orderd by rank top 100
using this code
let players: any = await Player.findAll({
attributes: [
'name',
'profile.numberOfKills',
'profilepower',
'profile.rankId',
],
include: [
{
model: Profile,
include: [
{
model: Level,
attributes: ['name'],
as: 'rank',
},
],
},
],
order: ['profile.numberOfKills', 'DESC'],
limit: 100,
});
"message": "Cannot read properties of undefined (reading 'type')"
what to do
using sequelize and not literal query
The order should be an array that contains either another array per field you want to sort on or functions like sequelize.random(), sequelize.col('name'), etc.
Change:
order: ['profile.numberOfKills', 'DESC'],
to:
order: [
['profile.numberOfKills', 'DESC'],
],
I'm using literal and it works!
order: [
[sequelize.literal('`profile.numberOfKills`'), 'DESC']
]

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 - SQL Server - order by for association tables

I have 3 tables such as user, userProfile and userProfileImages. User is mapping with userPrfoile as has many and userProfile is mapping with userProfileImages as has many.
I need to write the order by query in userProfileImages, I tried as below, but no luck.
User.findById(uID, {
include: [
model: sequelize.models.userProfile
as: userProfile,
include: [
{
model: sequelize.models.userProfileImages,
as: 'profileImages',
}
],
order: [[sequelize.models.userProfileImages.id, "desc"]]
// order: [["id", "desc"]] --> Tried this way also no luck
] }
I am getting the result, but userProfilePicture table's result is not as desc.
Kindly give the solutions
From Sequelize offical docs:
// Will order by an associated model's created_at using an association object. (preferred method)
[Subtask.associations.Task, 'createdAt', 'DESC'],
// Will order by a nested associated model's created_at using association objects. (preferred method)
[Subtask.associations.Task, Task.associations.Project, 'createdAt', 'DESC'],
By referring above syntax, Update your order option like below
User.findById(uID, {
include: [{
model: sequelize.models.userProfile
as: userProfile,
include: [{
model: sequelize.models.userProfileImages,
as: 'profileImages',
}],
order: [['profileImages','id', 'desc']]
}]
});
Official Documentations: http://docs.sequelizejs.com/manual/tutorial/querying.html#ordering
Refer this thread for more solutions: https://github.com/sequelize/sequelize/issues/4553
Update your order in association like below
User.findById(uID, {
include: [
model: sequelize.models.userProfile,
as: userProfile,
include: [{
model: sequelize.models.userProfileImages,
as: 'profileImages',
separate:true, <-- Magic here
order: [['id', 'desc']]
}],
]});

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