如何在 NodeJS Sequelize 中按查询计算组

Posted

技术标签:

【中文标题】如何在 NodeJS Sequelize 中按查询计算组【英文标题】:How to count a group by query in NodeJS Sequelize 【发布时间】:2015-07-04 07:58:21 【问题描述】:

在 Rails 中,我可以执行一个简单的 ORM 查询来查询模型拥有的点赞数:

    @records = Model
        .select( 'model.*' )
        .select( 'count(likes.*) as likes_count' )
        .joins( 'LEFT JOIN likes ON model.id = likes.model_id' )
        .group( 'model.id' )

这会生成查询:

SELECT  models.*, count(likes.*) as likes_count
FROM "models" JOIN likes ON models.id = likes.model_id
GROUP BY models.id

在 Node Sequelize 中,任何类似的尝试都会失败:

return Model.findAll(
    group: [ '"Model".id' ],
    attributes: ['id', [Sequelize.fn('count', Sequelize.col('"Likes".id')), 'likes_count']],
    include: [ attributes: [], model: Like ],
);

这会生成查询:

SELECT
    Model.id,
    count(Likes.id) AS likes_count,
    Likes.id AS Likes.id           # Bad!
FROM Models AS Model
LEFT OUTER JOIN Likes
    AS Likes
    ON Model.id = Likes.model_id
GROUP BY Model.id;

哪个会产生错误:

column "Likes.id" must appear in the GROUP BY clause or be used in an aggregate function

它错误地选择了likes.id,我不知道为什么,也不知道如何摆脱它。

【问题讨论】:

总是选择加入模型的 id 是技术性的后续,并且不能被禁用。尝试将 likes.id 添加到您的组子句中 这个问题被mod删除了,答案是不要使用Sequelize。它经常产生使查询崩溃的无效 SQL(你有一份工作)。 Knex 查询构建器是一个更好的工具,它提供了与 rails 相同的关于 sql 的轻抽象。 Sql 已经是一个很好的抽象,不要让 Sequelize 对你不利。 @andy-ray 哪个版本的续集...? 你可以使用findAndCountAll 方法。请验证***.com/a/52857907/1709558 【参考方案1】:

This sequelize github issue 看起来完全像你的情况:

User.findAll(
  attributes: ['User.*', 'Post.*', [sequelize.fn('COUNT', 'Post.id'), 'PostCount']],
  include: [Post]
);

【讨论】:

【参考方案2】:

要解决这个问题,我们需要升级到最新版本的 sequelize 并包含 raw = true, 这是我在经过大量迭代和偏离路线谷歌搜索后所做的事情。

 getUserProjectCount: function (req, res) 
        Project.findAll(
            
                attributes: ['User.username', [sequelize.fn('COUNT', sequelize.col('Project.id')), 'ProjectCount']],
                include: [
                    
                        model: User,
                        attributes: [],
                        include: []
                    
                ],
                group: ['User.username'],
                raw:true
            
        ).then(function (projects) 
            res.send(projects);
        );
    

我的参考模型在哪里

//user
var User = sequelize.define("User", 
    username: Sequelize.STRING,
    password: Sequelize.STRING
);

//project
var Project = sequelize.define("Project", 
    name: Sequelize.STRING,
    UserId:
         type:Sequelize.INTEGER,
         references: 
                 model: User,
                  key: "id"
         
    
);

Project.belongsTo(User);
User.hasMany(Project);

迁移 ORM 后,在我的 postgres 服务器中创建“用户”和“项目”表。 这是 ORM 的 SQL 查询

SELECT 
  "User"."username", COUNT("Project"."id") AS "ProjectCount" 
 FROM 
    "Projects" AS "Project" 
    LEFT OUTER JOIN "Users" AS "User" ON "Project"."UserId" = "User"."id" 
 GROUP BY 
   "User"."username";

【讨论】:

我认为这是一个很好的例子,说明为什么要不惜一切代价避免使用 Sequelize。这不仅仅是对 SQL 的泄漏抽象,他们发明了自己的无意义抽象来修复自己的软件,例如 "raw": true。 SQL 已经是一个很好的抽象,Sequelize 只是在它之上引入了新的 bug。 +1 用于提示“raw = true”。没有它,我的续集(版本 3.27.0)表现得很疯狂。简单示例:model.findAll attributes: ['name', sequelize.fn('sum', sequelize.col('value'))] group: ['name'] 输出的结构按“名称”分组(没关系),但不是 sum(value),而是其他第三列,绝对不相关。 @AndyRay 你能推荐一个更好的节点 ORM 吗? (使用纯 db 驱动程序(例如 sqlite)需要一些样板文件)

以上是关于如何在 NodeJS Sequelize 中按查询计算组的主要内容,如果未能解决你的问题,请参考以下文章

nodejs:sequelize数据库查询的Op方法

如何在 Sequelize 中按多对多关系排序?

NodeJS Sequelize 从查询返回数据

如何防止nodejs中的sql注入和续集? [关闭]

如何在 SEQUELIZE (nodeJS) 中创建触发器?

nodejs使用Sequelize框架操作数据库