一个组织可以有多个理由,可用的理由数量可以每天变化 .
用户应该获得所有理由的列表,而不管它们在给定/指定日期是否可用 . 将向用户显示的是,在给定日期内某些地点不可用 .
代码中的休息[“可用”]表示 .
So I am doing this work manually in javascript, can not I some how shift the javascript logic to the Sequelize as well? so that it returns me the "available" status as well as "average" in the response.
实际上,我有大量的数据,我相信在JS代码中循环并不是一种有效的方法 .
因此,我认为逻辑必须转移到数据库,但我不确定是否使用Sequelize .
数据库表,它们的关系和JS代码如下 .
Organization.model.js
module.exports = function(sequelize, DataTypes) {
let Organization = sequelize.define('Organization', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
unique: true,
allowNull: false
},
name: {
type: DataTypes.STRING,
primaryKey: true,
}
}, {
timestamps: false,
freezeTableName: true,
tableName: "Organization",
underscored: false
});
Organization.associate = function(models) {
Organization.hasMany(models.Grounds, {
onDelete: 'cascade',
hooks: true,
foreignKey: 'OrganizationName',
sourceKey: 'name'
});
};
return Organization;
};
Grounds.model.js
module.exports = function(sequelize, DataTypes) {
let Grounds = sequelize.define('Grounds', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
OrganizationName: {
type: DataTypes.STRING,
references: {
model: 'Organization',
key: 'name'
}
},
NumbersAvailable: {
type: DataTypes.INTEGER
},
Date: DataTypes.DATEONLY
}, {
timestamps: false,
freezeTableName: true,
tableName: "Grounds",
underscored: false
});
Grounds.associate = function(models) {
Grounds.belongsTo(models.Organization, {
foreignKey: 'OrganizationName',
targetKey: 'name'
});
};
return Grounds;
};
JavaScript Logic:
//Get all the Grounds, in the specified Dates, e.g: '2018-05-01' & '2018-05-04'
let organizations = await Organization.findAll({
include: [
model: Grounds,
where: {
Date: {
$gte: '2018-05-01',
$lte: '2018-05-04'
}
}
]
});
//Calculate the Grounds Availability, in the specified Dates, e.g: '2018-05-01' & '2018-05-04'
let finalResult = organizations.map(function(currVal){
let organization = currVal.dataValues;
let {Grounds, ...rest} = organization;
rest["available"] = true; //Custom Key.
rest["average"] = 0; //Custom Key.
Grounds.forEach(function(ground){
let Date = ground.Date;
rest["average"] += ground.NumbersAvailable;
let number = ground.NumbersAvailable;
if(number == 0) rest["available"] = false;
});
rest["average"] = rest["average"]/Grounds.length;
});
Sample Table Data:
Organization TABLE:
id name
---------------------------
1 authority1
2 authority2
3 authority3
Grounds TABLE:
id NumbersAvailable OrganizationName Date GroundName
----------------------------------------------------------------------------
1 5 authority1 2018-05-01 someName
2 3 authority1 2018-05-02 someName
3 6 authority1 2018-05-03 someName
4 2 authority1 2018-05-04 someName
5 7 authority2 2018-05-01 someName
6 3 authority2 2018-05-02 someName
7 0 authority2 2018-05-03 someName
8 1 authority2 2018-05-04 someName
9 2 authority3 2018-05-01 someName
10 1 authority3 2018-05-02 someName
11 3 authority3 2018-05-03 someName
12 1 authority3 2018-05-04 someName
1 回答
将逻辑移回数据层的方法是使用view或database function(链接到Postgres文档;其他数据库可能使用"procedure"而不是"function") . 由于您在此处的具体案例涉及对所有组织及其理由运行一些简单的计算,因此查询将这两个表与
GROUP BY
和某些聚合连接的查询就足够了 . 就Sequelize而言,您可以将视图视为只读模型;每this issue,唯一的问题是你不能sync
它 .如果你需要一个函数,这就是事情开始变得多毛的地方 . 如何实现函数取决于您正在使用的SQL的方言,因为每个数据库都有自己的语言怪癖(SQL Server使用
SELECT TOP n
而不是SELECT .... LIMIT n
,依此类推) . 这里's where you run into the first potential issue -- you'现在被锁定到那个数据库服务器,无论是Postgres,SQL Server还是你有什么 . 如果要支持其他数据库,则需要将函数移植到其方言中 .使用函数的第二个问题是,据我所知,Sequelize没有提供一种简单的方法来执行返回表格结果的数据库函数 - 其原因在于它像其他对象关系映射器一样,抽象出方言等特殊性离开并且只提供一个接口,你可以编写
SELECT
,INSERT
等语句的基本套件 . 因此忽略了函数 . 要执行一个,您需要使用其raw query功能 .