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

如何基于MongoDB唯一字段实现分页并获取唯一记录总数?

解决方案

1. 修复唯一记录总数统计的问题

你之前的await Token.find().distinct('token_id').countDocuments().exec()写法错误,因为distinct()返回的是包含唯一值的数组Promise,并非Mongoose的Query对象,无法链式调用countDocuments()。要高效统计唯一token_id的数量,直接用聚合的$group+$count即可,无需拉取全量数据:

const getUniqueTokenCount = async () => {
  const result = await Token.aggregate([
    { $group: { _id: '$token_id' } },
    { $count: 'total' }
  ]).exec();
  return result.length > 0 ? result[0].total : 0;
};

2. 结合分页与总数的高效聚合方案

如果想通过一次数据库请求同时拿到分页数据和唯一总数,可使用$facet聚合阶段,它能在一个聚合管道中并行执行多个子管道,分别返回不同结果:

const getUniqueTokensWithPagination = async (offset = 0, limit = 100) => {
  const [result] = await Token.aggregate([
    // 按token_id分组,保留每组第一条文档实现去重
    {
      $group: {
        _id: '$token_id',
        doc: { $first: '$$ROOT' }
      }
    },
    // 并行处理总数统计和分页逻辑
    {
      $facet: {
        totalCount: [{ $count: 'value' }],
        paginatedData: [
          { $skip: offset },
          { $limit: limit },
          { $replaceRoot: { newRoot: '$doc' } }
        ]
      }
    }
  ]).exec();

  return {
    total: result.totalCount.length > 0 ? result.totalCount[0].value : 0,
    data: result.paginatedData
  };
};

代码说明

  • $group阶段:按token_id分组,用$first保留每组的第一条文档,完成去重操作。
  • $facet阶段:
    • totalCount子管道:对分组后的结果计数,得到唯一记录的总数。
    • paginatedData子管道:先执行$skip和$limit完成分页,再用$replaceRoot将分组后保留的文档恢复为原结构。
  • 该方案仅需一次数据库请求,全程在MongoDB端处理数据,不会将全量数据加载到Node应用内存中。

替代方案:分开查询总数与分页数据

若不想使用$facet,也可分开调用两个聚合方法(会多一次数据库请求):

// 获取唯一记录总数
const total = await getUniqueTokenCount();
// 获取分页去重数据
const data = await Token.aggregate([
  { $group: { _id: '$token_id', doc: { $first: '$$ROOT' } } },
  { $replaceRoot: { newRoot: '$doc' } },
  { $skip: offset },
  { $limit: limit }
]).exec();

return { total, data };

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:57:16