You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从MongoDB迁移至PostgreSQL:Mongoose聚合转Sequelize实现

Sequelize替代Mongoose分组聚合的实现方案

原Mongoose代码的核心逻辑是:按name字段分组,保留每个分组中最先出现的完整文档,最终仅返回该文档的name和version字段。以下是对应的Sequelize实现方案,适配PostgreSQL特性:

方案一:利用PostgreSQL DISTINCT ON(简洁高效)

PostgreSQL的DISTINCT ON语法可以直接实现"按字段分组取第一条"的需求,和原逻辑完全匹配:

async listTestModels(): Promise<TestModel[]> {
  return TestModel.findAll({
    attributes: ['name', 'version'],
    distinct: true,
    // 排序规则决定分组内取哪条记录,和MongoDB的$first逻辑对应
    // 若原逻辑是按插入顺序取第一条,可替换为['name', 'ASC', 'id', 'ASC']
    order: [['name', 'ASC']],
    // 可选:返回纯JS对象而非Sequelize实例
    raw: true
  });
}

方案二:窗口函数(灵活适配复杂场景)

如果需要更精确控制分组内的筛选规则(比如按特定字段排序取第一条),可以用ROW_NUMBER()窗口函数实现:

async listTestModels(): Promise<TestModel[]> {
  const { Op } = require('sequelize');
  
  // 子查询:给每个name分组的记录按指定规则编号
  const subQuery = TestModel.findAll({
    attributes: [
      'name',
      'version',
      [TestModel.sequelize.literal('ROW_NUMBER() OVER (PARTITION BY name ORDER BY createdAt ASC)'), 'row_num']
    ],
    raw: true
  });

  // 主查询:仅取每个分组中编号为1的记录
  return TestModel.findAll({
    attributes: ['name', 'version'],
    where: {
      [Op.and]: TestModel.sequelize.literal(`(name, version) IN (SELECT name, version FROM (${subQuery.query}) AS sub WHERE row_num = 1)`)
    },
    raw: true
  });
}

注意事项

  • 确保Sequelize的TestModel模型已正确映射PostgreSQL表结构,name和version字段对应无误。
  • 若原Mongoose的$first依赖插入顺序,需在排序规则中加入自增主键(如id)或创建时间字段(如createdAt),保证取数逻辑一致。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:31:15