使用Sequelize

时间:2016-06-14 16:46:16

标签: mysql node.js sequelize.js

我有两个表,locationssensorssensors中的每个条目都有一个指向locations的外键。使用Sequelize,如何获取locations中的所有条目以及sensors中与locations中每个条目相关联的条目总数?

原始SQL:

SELECT 
    `locations`.*,
    COUNT(`sensors`.`id`) AS `sensorCount` 
FROM `locations` 
JOIN `sensors` ON `sensors`.`location`=`locations`.`id`;
GROUP BY `locations`.`id`;

型号:

module.exports = function(sequelize, DataTypes) {
    var Location = sequelize.define("Location", {
        id: {
            type: DataTypes.INTEGER.UNSIGNED,
            primaryKey: true
        },
        name: DataTypes.STRING(255)
    }, {
        classMethods: {
            associate: function(models) {
                Location.hasMany(models.Sensor, {
                    foreignKey: "location"
                });
            }
        }
    });

    return Location;
};


module.exports = function(sequelize, DataTypes) {
    var Sensor = sequelize.define("Sensor", {
        id: {
            type: DataTypes.INTEGER.UNSIGNED,
            primaryKey: true
        },
        name: DataTypes.STRING(255),
        type: {
            type: DataTypes.INTEGER.UNSIGNED,
            references: {
                model: "sensor_types",
                key: "id"
            }
        },
        location: {
            type: DataTypes.INTEGER.UNSIGNED,
            references: {
                model: "locations",
                key: "id"
            }
        }
    }, {
        classMethods: {
            associate: function(models) {
                Sensor.belongsTo(models.Location, {
                    foreignKey: "location"
                });

                Sensor.belongsTo(models.SensorType, { 
                    foreignKey: "type"
                });
            }
        }
    });

    return Sensor;
};

4 个答案:

答案 0 :(得分:22)

findAll()使用include()sequelize.fn()使用COUNT

Location.findAll({
    attributes: { 
        include: [[Sequelize.fn("COUNT", Sequelize.col("sensors.id")), "sensorCount"]] 
    },
    include: [{
        model: Sensor, attributes: []
    }]
});

或者,您可能还需要添加group

Location.findAll({
    attributes: { 
        include: [[Sequelize.fn("COUNT", Sequelize.col("sensors.id")), "sensorCount"]] 
    },
    include: [{
        model: Sensor, attributes: []
    }],
    group: ['Location.id']
})

答案 1 :(得分:2)

用于使用Sequelize计算关联条目

Location.findAll({
    attributes: { 
        include: [[Sequelize.fn('COUNT', Sequelize.col('sensors.location')), 'sensorCounts']] 
    }, // Sequelize.col() should contain a attribute which is referenced with parent table and whose rows needs to be counted
    include: [{
        model: Sensor, attributes: []
    }],
    group: ['sensors.location'] // groupBy is necessary else it will generate only 1 record with all rows count
})

注意:

某种程度上,此查询会生成类似 sensors.location的错误,该查询在字段列表中不存在。发生这种情况是由于上述续集查询形成了subQuery。

因此,解决方案是提供subQuery:如示例一样为false

Location.findAll({
        subQuery: false,
        attributes: { 
            include: [[Sequelize.fn('COUNT', Sequelize.col('sensors.location')), 'sensorCounts']] 
        },
        include: [{
            model: Sensor, attributes: []
        }],
        group: ['sensors.location']
    })

注意: **有时这还会生成mysql配置错误bcz,默认情况下,该配置在sqlMode中仅包含full-group-by,需要将其删除才能正常工作。

错误看起来像这样。.**

错误:SELECT列表的表达式#1不在GROUP BY子句中,并且包含未聚合的列'db.table.id',该列在功能上不依赖于GROUP BY子句中的列;这与sql_mode = only_full_group_by

不兼容

因此,要解决此错误,请遵循以下答案

SELECT list is not in GROUP BY clause and contains nonaggregated column .... incompatible with sql_mode=only_full_group_by

现在,这将成功生成所有关联的计数

希望这对您或其他人有帮助!

答案 2 :(得分:1)

Location.findAll({
        attributes: { 
            include: [[Sequelize.fn("COUNT", Sequelize.col("sensors.id")), "sensorCount"]] 
        },
        include: [{
            model: Sensor, attributes: []
        }]
    });

它有效。但是当我添加"限制"时,我收到错误:传感器未定义

答案 3 :(得分:0)

如何为它定义一个数据库视图,然后为该视图定义一个模型?只要您需要传感器的数量,您就可以获取与查询中包含的视图的关系。这样代码可能看起来更干净,但我不知道是否会有性能成本。其他人可能会回答...

CREATE OR REPLACE VIEW view_location_sensors_count AS
select "locations".id as "locationId", count("sensors".id) as "locationSensorsCount"
from locations
left outer join sensors on sensors."locationId" = location.id
group by location.id

为视图定义模型时,删除 id 属性并将 locationId 设置为主键。 您的模型可能如下所示:

const { Model, DataTypes } = require('sequelize')

const attributes = {
    locationID: {
        type: DataTypes.UUIDV4, // Or whatever data type is your location ID
        primaryKey: true,
        unique: true
    },
    locationSensorsCount: DataTypes.INTEGER
}

const options = {
    paranoid: false,
    modelName: 'ViewLocationSensorsCount',
    tableName: 'view_location_sensors_count',
    timestamps: false
}


/**
 * This is only a database view. It is not an actual table, so 
 * DO NOT ATTEMPT insert, update or delete statements on this model
 */
class ViewLocationSensorsCount extends Model {
    static associate(models) {
        ViewLocationSensorsCount.removeAttribute('id')
        ViewLocationSensorsCount.belongsTo(models.Location, { as:'location', foreignKey: 'locationID' })
    }


    static init(sequelize) {
        this.sequelize = sequelize
        return super.init(attributes, {...options, sequelize})
    }
}

module.exports = ViewLocationSensorsCount

最后,在 Location 模型中,您设置了与 Sensor 模型的 hasOne 关系。