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

Mongoose aggregate统计Order总销售额报Cast to ObjectId错误

问题描述

使用Mongoose的aggregate聚合函数统计Order模型总销售额时,触发如下报错:

CastError: Cast to ObjectId failed for value "totalsales" (type string) at path "_id" for model "Order"
已确认$group阶段传入的_id为null,写法与官方文档示例一致,但无法定位报错来源。
对应接口代码:

router.get("/get/totalsales", async (req, res) => {
  const totalSales = await Order.aggregate([
    {
      $group: {
        _id: null,
        totalsales: { $sum: "$totalPrice" },
      },
    },
  ]);
  // console.log(totalSales);
});

Order模型Schema定义:

const mongoose = require("mongoose");

const orderSchema = mongoose.Schema({
  orderItems: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "OrderItem",
      required: true,
    },
  ],
  shippingAddress1: {
    type: String,
    required: true,
  },
  shippingAddress2: {
    type: String,
  },
  city: {
    type: String,
    required: true,
  },
  zip: {
    type: String,
    required: true,
  },
  country: {
    type: String,
    required: true,
  },
  phone: {
    type: String,
    required: true,
  },
  status: {
    type: String,
    required: true,
    default: "Pending",
  },
  totalPrice: {
    type: Number,
  },
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
  },
  dateOrdered: {
    type: String,
    default: Date.now,
  },
});

orderSchema.virtual("id").get(function () {
  return this._id.toHexString();
});

orderSchema.set("toJSON", { virtuals: true });

exports.Order = mongoose.model("Order", orderSchema);
报错根因

报错和聚合逻辑无关,是路由匹配顺序错误导致的:

  • 你的/get/totalsales路由定义在/get/:id这类带动态参数的路由之后
  • 请求/get/totalsales时,Express会按照路由定义顺序从上到下匹配,先命中了前面的动态路由,把路径段totalsales当做id参数传入
  • 动态路由内的逻辑会调用Order.findById(id)类方法,Mongoose尝试把字符串totalsales转换为ObjectId类型,直接触发类型转换报错
解决方案

任选一种即可修复:

  • 调整路由定义顺序,把完全匹配的静态路由/get/totalsales挪到所有/get/:xxx形式的动态路由前面,保证静态路由优先被匹配
  • 给所有带ObjectId参数的动态路由增加前置校验,参数格式不符合要求直接返回错误,避免无效数据库查询,示例代码:
const mongoose = require('mongoose');

// 动态路由示例
router.get("/get/:id", async (req, res) => {
  const { id } = req.params;
  if (!mongoose.isValidObjectId(id)) {
    return res.status(400).send({ message: "无效的订单ID" });
  }
  // 后续正常查询逻辑
  const order = await Order.findById(id);
  // 剩余业务逻辑...
})

注:你当前写的聚合管道语法完全正确,_id: null用于统计全集合聚合结果的写法不需要修改。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:18:15