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

Sequelize调用findAll查询时如何跳过指定列重复的非首条记录

Sequelize按指定列去重、保留首条匹配记录的实现方式

Sequelize没有提供直接按非主键列去重的开箱即用findAll参数,你可以根据自己使用的数据库类型、数据量大小选择以下两种方案实现需求:

方案1:数据库层去重(性能最优,推荐大数据量场景)

通用写法(支持MySQL 8.0+、PostgreSQL、SQL Server等所有支持窗口函数的数据库)

通过ROW_NUMBER()窗口函数按placeId分区,按你指定的distance排序规则给同分区的记录编号,只取每个分区编号为1的记录即可,改造后的代码如下:

const items = await models.Item.findAll({
  attributes: {
    include: [
      [
        sequelize.literal(`ROW_NUMBER() OVER (PARTITION BY placeId ORDER BY ${distance})`),
        'rowNum'
      ]
    ]
  },
  where: {
    [Op.and]: [
      sequelize.where(distance, { [Op.lte]: radius }),
      sequelize.where(descriptionFilter, { [Op.gte]: 2 }),
      { name: { [Op.notLike]: `%Example%` } },
      { userId: { [Op.not]: me.id } }
    ]
  },
  having: sequelize.literal('rowNum = 1'),
  order: distance,
  limit: 25,
  subQuery: false
})

PostgreSQL专属简化写法

如果你用的是PostgreSQL数据库,可以直接用Sequelize原生支持的distinctOn配置,不需要写原生窗口函数:

const items = await models.Item.findAll({
  distinctOn: ['placeId'],
  where: {
    [Op.and]: [
      sequelize.where(distance, { [Op.lte]: radius }),
      sequelize.where(descriptionFilter, { [Op.gte]: 2 }),
      { name: { [Op.notLike]: `%Example%` } },
      { userId: { [Op.not]: me.id } }
    ]
  },
  // 注意:DISTINCT ON要求排序规则的最左侧字段必须包含distinctOn指定的列
  order: [distance, ['placeId', 'ASC']],
  limit: 25
})

方案2:Node内存端去重(小数据量场景改造成本最低)

如果你的查询结果集规模不大,可以先把符合筛选条件的记录查出来,再用JS代码按placeId去重,不需要改动原有查询的SQL逻辑:

// 适当放大初始查询的limit,避免去重后结果不足25条
const rawItems = await models.Item.findAll({
  where: {
    [Op.and]: [
      sequelize.where(distance, { [Op.lte]: radius }),
      sequelize.where(descriptionFilter, { [Op.gte]: 2 }),
      { name: { [Op.notLike]: `%Example%` } },
      { userId: { [Op.not]: me.id } }
    ]
  },
  order: distance,
  limit: 100 // 可根据实际placeId重复率调整这个值
})

// 遍历去重,保留同placeId的第一条记录
const visitedPlaceIds = new Set()
const items = rawItems.filter(item => {
  if (visitedPlaceIds.has(item.placeId)) return false
  visitedPlaceIds.add(item.placeId)
  return true
}).slice(0, 25)

注意:内存去重方案需要根据实际业务中placeId的重复率调整初始查询的limit值,避免去重后最终返回的结果条数不足25条。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:51:21