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

如何在MongoDB中使用Group分组查询按城市统计消费总金额?

MongoDB $group 聚合实现按城市统计总价

前置注意事项

你当前定义的Schema中price字段为String类型,直接参与数值求和会出现计算异常,优先建议将该字段类型修改为Number,减少聚合时的类型转换开销。如果暂时无法调整Schema结构,可以在聚合阶段增加类型转换逻辑兼容。

$group 核心逻辑说明

$group是MongoDB聚合管道的核心阶段之一,作用是按指定的分组键对文档归类,配合累加器完成同组数据的统计计算:

  • _id字段为必填项,用于指定分组依据的字段,这里按城市分组就填'$city'
  • 累加器支持求和、平均值、最大/最小值等统计场景,本次需求用$sum累加器计算同组价格总和即可

可直接运行的实现代码

方案1:修改Schema为最优实现(推荐)

先调整Schema定义,将price改为数值类型:

const historySchema = mongoose.Schema(
  {
    city: { type: String, required: true },
    price: { type: Number, required: true }, // 调整为Number类型存储数值
    customerId: {type: String, required: true}
  },
);
const History = mongoose.model('History', historySchema);

编写聚合查询+结果格式转换逻辑:

async function getCityPriceTotal() {
  // 执行聚合查询
  const aggRes = await History.aggregate([
    {
      $group: {
        _id: '$city', // 按city字段分组
        totalPrice: { $sum: '$price' } // 累加同组所有文档的price值
      }
    }
  ]);

  // 将聚合返回的数组转换为你需要的键值对结构
  const finalResult = {};
  aggRes.forEach(item => {
    finalResult[item._id] = item.totalPrice;
  });

  return finalResult;
}

方案2:兼容String类型price的实现

如果暂时无法修改Schema字段类型,可以在聚合时增加类型转换,避免计算错误:

async function getCityPriceTotal() {
  const aggRes = await History.aggregate([
    {
      $group: {
        _id: '$city',
        totalPrice: { 
          $sum: {
            $convert: {
              input: '$price',
              to: 'double', // 将字符串类型的price转为双精度数值
              onError: 0, // 遇到非数字内容时默认按0计算,避免聚合中断
              onNull: 0 // 字段为空时默认按0计算
            }
          }
        }
      }
    }
  ]);

  const finalResult = {};
  aggRes.forEach(item => {
    finalResult[item._id] = item.totalPrice;
  });

  return finalResult;
}

最终返回格式

调用上述方法后,得到的返回结果完全匹配你的需求:

{
  "City A": 1000,
  "City B": 2000,
  "City C": 3000
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:27:08