有两个联结表可供考虑,即category_post 和user_like 表。这些可以使用many to many associations 处理。为简单起见,在下面的代码中,我将 user_like 表视为父表 posts 的简单子表,留下一个剩余的联结表来考虑。
此外,打开sequelize logging 对处理困难的查询有很大帮助。
以下是我将如何设置映射。
let Category = sequelize.define('categories', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
category_name: DataTypes.STRING,
detail: DataTypes.STRING
},
{
tableName: 'categories',
timestamps: false
})
let Post = sequelize.define('posts', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
title: DataTypes.STRING,
image_url: DataTypes.STRING
},
{
tableName: 'posts',
timestamps: false
})
let UserLike = sequelize.define('UserLike', {
post_id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true
}
},
{
tableName: 'user_likes',
timestamps: false
})
Category.belongsToMany(Post, {
through: 'category_posts',
timestamps: false,
foreignKey: 'category_id',
otherKey: 'post_id'
})
Post.belongsToMany(Category, {
through: 'category_posts',
timestamps: false,
foreignKey: 'post_id',
otherKey: 'category_id'
})
Post.hasMany(UserLike, {
foreignKey: 'post_id',
sourceKey: 'id'
})
UserLike.belongsTo(Post, {
foreignKey: 'post_id',
targetKey: 'id'
})
然后我会使用这样的子查询。请注意,为了使其成为sequelize subquery,文字选择语句周围的括号是必要的。
let results = await Category.findAll({
attributes: {
exclude: [ 'detail' ]
},
where: { id: request.params.id },
include: {
model: Post,
attributes: {
include: [
[ sequelize.cast(sequelize.literal('(select count(*) from user_likes as ul where ul.post_id = posts.id)'), 'integer'), 'likes' ]
]
}
}
})
这会产生以下结果:
[
{
"id": 1,
"category_name": "category 1",
"posts": [
{
"id": 1,
"title": "Post 1",
"image_url": "http://example.com/image1.png",
"likes": 3,
"category_posts": {
"category_id": 1,
"post_id": 1
}
},
{
"id": 2,
"title": "Post 2",
"image_url": "http://example.com/image2.png",
"likes": 2,
"category_posts": {
"category_id": 1,
"post_id": 2
}
}
]
}
]
或者,正如 HarshIT 所建议的那样,您可以使用聚合和 group by 子句与以下查询:
let results = await Category.findAll({
attributes: {
exclude: [ 'detail' ],
include: [[sequelize.cast(sequelize.fn('COUNT', Sequelize.col('posts->UserLikes.post_id')), 'integer'), 'total_likes']]
},
where: { id: request.params.id },
include: {
model: Post,
include: {
model: UserLike
}
},
group: [
'categories.id',
'posts.id',
'posts->category_posts.category_id',
'posts->category_posts.post_id',
'posts->UserLikes.post_id',
'posts->UserLikes.user_id'
]
})
会产生如下形式的结果:
[
{
"id": 1,
"category_name": "category 1",
"total_likes": 1,
"posts": [
{
"id": 1,
"title": "Post 1",
"image_url": "http://example.com/image1.png",
"category_posts": {
"category_id": 1,
"post_id": 1
},
"UserLikes": [
{
"post_id": 1,
"user_id": 5
},
{
"post_id": 1,
"user_id": 6
},
{
"post_id": 1,
"user_id": 9
}
]
},
{
"id": 2,
"title": "Post 2",
"image_url": "http://example.com/image2.png",
"category_posts": {
"category_id": 1,
"post_id": 2
},
"UserLikes": [
{
"post_id": 2,
"user_id": 5
},
{
"post_id": 2,
"user_id": 8
}
]
}
]
}
]