如何计算postgres数据库中sequelize中的关联

How to count associations in sequelize in postgres database

我使用 sequelize 框架在 Node.js 中开发了 APIs。我使用 Postgres 数据库。请在下面找到我的 table 结构如下。

category post category_post user_like
id id category_id user_id
category_name title post_id post_id
detail image_url

我需要开发一个 API 来根据提供的类别 ID 和 return 类别的 post 过滤类别,每个 post 应该包含其中的喜欢总数.

示例 JSON 响应如下:

{
    "data":{
        "id":1,
        "category_name":"category 1",
        "posts":[
            {
                "id":1,
                "title":"post 1",
                "total_likes":50,
                "image_url":"image.png"
            }
        ]
    },
    "success":true
}

请找到我的代码如下:

sequelize.transaction().then(result => {
  return category.findOne({
    where: { "id": request.params.id }, include: [{
      model: post,
      as: "posts",
      attributes: ["id","title","image_url"],
      through: {
        attributes: []
      }
    }],
    attributes: ["id", "category_name"],
  });
}).then(posts => {
  let r = { "data": posts, "success": true }
  response.status(200).json(r)
}).catch(function (err) {
  console.log(err)
});

请指导我如何获得 post 的总点赞数。这个功能对我不起作用

有两个结点 table 供考虑,即 category_postuser_like table。这些可以使用 many to many associations 来处理。为简单起见,在下面的代码中,我将 user_like table 视为父 table posts 的一个简单子 table,剩下一个结 table 考虑。

此外,打开 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.

,文字 select 语句周围的括号是必需的
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
          }
        ]
      }
    ]
  }
]