I have setup a very basic minified playground for sequelize experiements to learn how it behaves on association records fetch. But i am not able to achieve the desired output.
Reproduceable Code
const Sequelize = require('sequelize');
const { fn } = Sequelize;
const sequelize = new Sequelize('playground', 'postgres', 'postgres', {
host: 'localhost',
dialect: 'postgres',
pool: {
max: 9,
min: 0,
idle: 10000
}
});
const Posts = sequelize.define('posts', {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
title: {
type: Sequelize.STRING
},
content: {
type: Sequelize.STRING
}
},
{
freezeTableName: true,
timestamps: false
}
);
const Comments = sequelize.define('comments', {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
postId: {
type: Sequelize.INTEGER,
references: {
model: 'posts',
key: 'id'
}
},
comment: {
type: Sequelize.STRING
}
},
{
freezeTableName: true,
timestamps: false
}
);
Posts.hasMany(Comments, {
foreignKey: 'postId'
})
let criteria = {
group: ['posts.id', 'comments.id'],
attributes: [
[fn('count', 'comments.id'), 'TotalComments']
],
include: [
{
model: Comments,
}
]
}
Posts.findAll(criteria).then(posts =>{
console.dir(JSON.parse(JSON.stringify(posts)), {depth: null, colors: true});
});
Problem Encountering
The problem is straight forward i want to add the child records count in the parent attributes eg the count of all comments in the every post returned, but the output i am getting is returning a fix count which is 1. I can simply iterate all posts and set TotalComments by reading the total length of comments included, but i want to do this using sequelize query, because that way i can apply some filter eg posts with comments between 6 to 10
Output Shown
[
{
id: 101,
title: 'The revolution in brain',
TotalComments: '1', //this count is not matched with below included comments count
comments: [
{ id: 15, postId: 101, comment: 'It helped me a lot' },
{ id: 13, postId: 101, comment: 'very disapointing' },
{ id: 12, postId: 101, comment: 'welldone' },
{ id: 14, postId: 101, comment: 'This post sucks' }
]
},
{
id: 102,
title: 'Making your hands dirty on Java',
TotalComments: '1',
comments: []
},
{
id: 100,
title: 'Earlier models of medical surgery',
TotalComments: '1',
comments: [
{ id: 10, postId: 100, comment: 'Appreciated your work' },
{ id: 11, postId: 100, comment: 'good' }
]
}
]
Output Desired
[
{
id: 101,
title: 'The revolution in brain',
TotalComments: 4,
comments: [
{ id: 15, postId: 101, comment: 'It helped me a lot' },
{ id: 13, postId: 101, comment: 'very disapointing' },
{ id: 12, postId: 101, comment: 'welldone' },
{ id: 14, postId: 101, comment: 'This post sucks' }
]
},
{
id: 102,
title: 'Making your hands dirty on Java',
TotalComments: 0,
comments: []
},
{
id: 100,
title: 'Earlier models of medical surgery',
TotalComments: 2,
comments: [
{ id: 10, postId: 100, comment: 'Appreciated your work' },
{ id: 11, postId: 100, comment: 'good' }
]
}
]
Generated SQL
SELECT "posts"."id", "posts"."title", count('comments.id') AS "TotalComments", "comments"."id" AS "comments.id", "comments"."postId" AS "comments.postId", "comments"."comment" AS "comments.comment" FROM "posts" AS "posts" LEFT OUTER JOIN "comments" AS "comments" ON "posts"."id" = "comments"."postId" GROUP BY "posts"."id", "comments"."id";
I solved the issue my self after a lot of searching, i hope it will help every body else if they encounter similar issue, basically i used the sequelize literal to insert some raw query to address the problem, the modified query criteria example is following
let criteria = {
group: ['posts.id', 'comments.id'],
attributes: [
'id',
'title',
[literal('(select count(comments.id) from comments where "comments"."postId" = "posts"."id")'), 'TotalComments']
],
include: [
{
model: Comments,
}
]
}
Posts.findAll(criteria).then(posts =>{
console.dir(JSON.parse(JSON.stringify(posts)), {depth: null, colors: true});
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.