Sequelize top 5 多对多关系

Sequelize top 5 relation many to many

我的项目中有两个模型。

  1. 订单
  2. 产品
  3. 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.

参考文献:

  1. Ordering by an aggregate (SUM or COUNT) function.
  2. Pagination.
  3. Binding syntax for the Query() function.