Sequelize top 5 多对多关系
Sequelize top 5 relation many to many
我的项目中有两个模型。
- 订单
- 产品
- OrderProducts(通过)(有数量列)
我需要某段时间内确认订单的购买最多的5个产品
OrderProducts.init({
order_id: DataTypes.INTEGER(4),
product_id: DataTypes.INTEGER(4),
qtd: DataTypes.INTEGER(4),
price: DataTypes.DECIMAL(15, 2),
})
Orders.init({
order_id: {
type: DataTypes.INTEGER(4),
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
client_id: DataTypes.INTEGER(4),
amount: DataTypes.DECIMAL(15,2),
status: {
type: DataTypes.ENUM([
'PENDING',
'CONFIRMED',
'PROGRESS',
'CANCELED',
]),
allowNull: false,
defaultValue: 'PENDING',
},
})
Products.init({
product_id: {
type: DataTypes.INTEGER(4),
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
title: DataTypes.STRING(256),
description: DataTypes.TEXT,
})
Orders.belongsToMany(Products, {foreignKey: 'order_id', through: OrderProducts, as: 'products'})
Products.belongsToMany(Orders, {foreignKey: 'product_id', through: OrderProducts})
一种解决方案是通过...
搜索 table
我假设 qtd
不知何故是“数量”字段。如果没有,并且每个订单每个产品类型只能有一个,那么请尝试切换到 COUNT()
功能。我还假设您在订单 table 上有一个购买日期时间,您自然会称其为 purchaseDate
.
const queryStartDate = moment().subtract(1, 'months').startOf('day');
const queryEndDate = moment().endOf('day');
Products.findAll({
offset: 0,
limit: 5,
attributes: ['product_id', 'title',
[sequelize.literal(`(
SELECT SUM(op.qty)
FROM OrderProducts AS op
INNER JOIN Orders o ON o.order_id = op.order_id
WHERE
op.product_id = Product.product_id
AND o.purchaseDate >= $startDate
AND o.purchaseDate <= $endDate
AND o.status = 'CONFIRMED'
)`, {
bind: {
startDate: queryStartDate,
endDate: queryEndDate,
},
}), 'summedQty']
],
order: [[sequelize.literal('summedQty'), 'DESC']]
});
// Note:
// - I'm assuming [OrderProducts] and [Orders] are the names of the actual SQL tables.
// - In contrast, the `Product.product_id` reference is to whatever Sequelize renders the Products table's alias as, in the SQL query. It'll be a reference to the parent of the sub-query. This may need tweaking but it should be good-to-go.
// - Were I you, I would put those statuses in a Look-up-Table. Enums are great in applications but strings/varchars are costly in databases.
// - I can't remember if the `Sequelize.literal()` function takes a `bind` attribute, like the `Sequelize.query()` function does. If not, you'll have to use string interpolation and format-out the dates.
参考文献:
我的项目中有两个模型。
- 订单
- 产品
- OrderProducts(通过)(有数量列)
我需要某段时间内确认订单的购买最多的5个产品
OrderProducts.init({
order_id: DataTypes.INTEGER(4),
product_id: DataTypes.INTEGER(4),
qtd: DataTypes.INTEGER(4),
price: DataTypes.DECIMAL(15, 2),
})
Orders.init({
order_id: {
type: DataTypes.INTEGER(4),
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
client_id: DataTypes.INTEGER(4),
amount: DataTypes.DECIMAL(15,2),
status: {
type: DataTypes.ENUM([
'PENDING',
'CONFIRMED',
'PROGRESS',
'CANCELED',
]),
allowNull: false,
defaultValue: 'PENDING',
},
})
Products.init({
product_id: {
type: DataTypes.INTEGER(4),
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
title: DataTypes.STRING(256),
description: DataTypes.TEXT,
})
Orders.belongsToMany(Products, {foreignKey: 'order_id', through: OrderProducts, as: 'products'})
Products.belongsToMany(Orders, {foreignKey: 'product_id', through: OrderProducts})
一种解决方案是通过...
搜索 table我假设 qtd
不知何故是“数量”字段。如果没有,并且每个订单每个产品类型只能有一个,那么请尝试切换到 COUNT()
功能。我还假设您在订单 table 上有一个购买日期时间,您自然会称其为 purchaseDate
.
const queryStartDate = moment().subtract(1, 'months').startOf('day');
const queryEndDate = moment().endOf('day');
Products.findAll({
offset: 0,
limit: 5,
attributes: ['product_id', 'title',
[sequelize.literal(`(
SELECT SUM(op.qty)
FROM OrderProducts AS op
INNER JOIN Orders o ON o.order_id = op.order_id
WHERE
op.product_id = Product.product_id
AND o.purchaseDate >= $startDate
AND o.purchaseDate <= $endDate
AND o.status = 'CONFIRMED'
)`, {
bind: {
startDate: queryStartDate,
endDate: queryEndDate,
},
}), 'summedQty']
],
order: [[sequelize.literal('summedQty'), 'DESC']]
});
// Note:
// - I'm assuming [OrderProducts] and [Orders] are the names of the actual SQL tables.
// - In contrast, the `Product.product_id` reference is to whatever Sequelize renders the Products table's alias as, in the SQL query. It'll be a reference to the parent of the sub-query. This may need tweaking but it should be good-to-go.
// - Were I you, I would put those statuses in a Look-up-Table. Enums are great in applications but strings/varchars are costly in databases.
// - I can't remember if the `Sequelize.literal()` function takes a `bind` attribute, like the `Sequelize.query()` function does. If not, you'll have to use string interpolation and format-out the dates.
参考文献: