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

MongoDB按numId分组获取最大count值技术实现问询

问题:按numId分组获取最高count的响应数据

我需要为每个numId获取最高的count数值,并在前端表格中展示。以下是我的数据库示例文档:

[
  { 
    "_id": { "$oid": "6294777f677b4c647e28771a" }, 
    "numId": "5", 
    "respondee": "0x9d95bcaa5b609fa97a7ec860bec115aa94f85ba9", 
    "__v": 0, 
    "originalResponse": "test2", 
    "submittedAt": { "$date": { "$numberLong": "1653897087357" } }, 
    "addresses": [ "0x39c878a3df98002ddba477a7aa0609fb5a27e2ff", "0xe3342d6522ad72f65d6b23f19b17e3fb12161f90" ], 
    "count": 2 
  },
  { 
    "_id": { "$oid": "6294836e677b4c647e287e93" }, 
    "numId": "5", 
    "respondee": "0xe3342d6522ad72f65d6b23f19b17e3fb12161f90", 
    "__v": 0, 
    "originalResponse": "test3", 
    "submittedAt": { "$date": { "$numberLong": "1653900142375" } }, 
    "addresses": [ ], 
    "count": 0 
  }
]

我编写了如下代码,但不确定如何按numId对结果进行分组:

import Response from '../../../models/Response.model';
import db from '../../../utils/config/db';
import nc from 'next-connect';
import { onError } from '../../../utils/error';

const handler = nc({ onError, });

// 获取全部数据
handler.get(async (req, res) => {
  await db.connect();
  let responses = await Response.find({ });
  // 按numId分组响应数据
  // 按count值升序排序响应数据
  responses = responses.sort((a, b) => {
    return a.count - b.count;
  });
  let topResponses = responses.filter((response) => {
    return response.count === responses[0].count;
  });
  // 检查提交者是否拥有最高count值的响应
  if ( topResponses.length > 0 && topResponses.find((response) => {
    return response.respondee === respondee;
  }) ) {
    // 获取响应数据
    let response = topResponses.find((response) => {
      return response.respondee === respondee;
    });
    // 获取响应内容
    let responseString = response.response;
    // 获取count值
    let count = response.count;
  }
  await db.disconnect();
});

export default handler;

解决方案:用MongoDB聚合管道实现分组取最大值

你的现有代码是在Node层处理排序和筛选,但没实现按numId分组,而且数据量大时客户端处理效率很低。咱们直接用MongoDB的聚合管道一步到位完成分组+取每个组最高count的需求,代码更简洁高效:

修改后的API代码

import Response from '../../../models/Response.model';
import db from '../../../utils/config/db';
import nc from 'next-connect';
import { onError } from '../../../utils/error';

const handler = nc({ onError });

handler.get(async (req, res) => {
  await db.connect();
  
  // 聚合管道:按numId分组,获取每个组内count最高的文档
  const topResponsesByNumId = await Response.aggregate([
    // 第一步:先按numId升序、count降序排序,确保每个numId下第一个文档是count最高的
    { $sort: { numId: 1, count: -1 } },
    // 第二步:按numId分组,保留每个组的第一个文档(即count最高的那条)
    {
      $group: {
        _id: "$numId", // 分组键:numId
        topResponse: { $first: "$$ROOT" } // 取分组内的第一个完整文档
      }
    },
    // 第三步:把结构扁平化,让返回的每个对象都是原文档格式,方便前端处理
    {
      $replaceRoot: { newRoot: "$topResponse" }
    }
  ]);

  await db.disconnect();
  
  // 返回处理好的数据给前端
  res.status(200).json(topResponsesByNumId);
});

export default handler;

代码说明

  1. $sort阶段:先按numId分组排序,再按count降序排列,这样同一个numId下,count最高的文档会排在最前面。
  2. $group阶段:以numId为分组键,用$first操作符取每个分组的第一个文档,也就是该numId下count最高的那条。
  3. $replaceRoot阶段:把嵌套的topResponse字段提升为根对象,让返回的数据结构和原文档一致,前端不需要额外处理嵌套。

前端表格展示参考

拿到API返回的数据后,你可以直接遍历渲染表格(以React为例):

export default function ResponseTable() {
  const [topResponses, setTopResponses] = useState([]);

  useEffect(() => {
    // 调用API获取数据
    fetch('/api/your-handler-path')
      .then(res => res.json())
      .then(data => setTopResponses(data));
  }, []);

  return (
    <table border="1">
      <thead>
        <tr>
          <th>numId</th>
          <th>最高Count值</th>
          <th>响应内容</th>
          <th>提交者</th>
        </tr>
      </thead>
      <tbody>
        {topResponses.map(item => (
          <tr key={item._id}>
            <td>{item.numId}</td>
            <td>{item.count}</td>
            <td>{item.originalResponse}</td>
            <td>{item.respondee}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

关于你代码中检查提交者的逻辑

如果需要判断某个特定respondee是否拥有某个numId的最高count响应,可以在获取到topResponsesByNumId后做筛选:

// 示例:从URL参数获取respondee
const respondee = req.query.respondee; 
// 判断该用户是否有最高响应
const hasTopResponse = topResponsesByNumId.some(item => item.respondee === respondee);
// 获取该用户的所有最高响应
const userTopResponses = topResponsesByNumId.filter(item => item.respondee === respondee);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 22:42:41