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

如何使用Mongoose计算用户的累计消费总额?

解决Mongoose关联文档累计消费计算的undefined问题

问题说明

现有两个Mongoose Schema:UserInfo包含用户名userName和关联History文档ID的数组historyList;History包含消费来源source、金额price、时间time字段。需要计算单个用户的累计消费总额,但当前代码循环获取price时返回undefined。

错误原因

  1. 未关联查询关联文档:原代码仅查询UserInfo,historyList中仅存储History的ObjectId,而非完整文档,自然无法直接获取price属性。
  2. 语法与遍历错误:total + =存在空格语法错误;且直接访问user.historyList.price,忽略了historyList是数组,需遍历每个元素。

正确实现方法

方法一:Populate关联文档后计算

先通过populate拉取关联的History完整文档,再遍历累加金额:

const mongoose = require("mongoose");
const UserInfo = require("../models/UserInfo"); // 替换为你的模型路径

exports.getMyCost = async (req, res, next) => {
  try {
    // 查询用户并关联拉取historyList对应的History文档
    const user = await UserInfo.findById(req.body._id).populate("historyList");
    let total = 0;

    // 遍历历史记录,累加金额(处理price为null/undefined的情况)
    user.historyList.forEach(history => {
      total += history.price || 0;
    });

    res.status(200).json({
      code: 200,
      total: total
    });
  } catch (error) {
    return next(
      res.status(400).json({
        code: 400,
        msg: error.message,
      })
    );
  }
};

方法二:MongoDB聚合查询(性能更优)

直接在数据库层面完成关联与聚合计算,无需拉取大量文档到内存,适合数据量大的场景:

const mongoose = require("mongoose");
const UserInfo = require("../models/UserInfo"); // 替换为你的模型路径

exports.getMyCost = async (req, res, next) => {
  try {
    const aggregateResult = await UserInfo.aggregate([
      // 匹配目标用户
      { $match: { _id: mongoose.Types.ObjectId(req.body._id) } },
      // 关联History集合(注意集合名为mongoose默认的小写复数形式histories)
      {
        $lookup: {
          from: "histories",
          localField: "historyList",
          foreignField: "_id",
          as: "historyList"
        }
      },
      // 计算累计消费总额,自动处理price为空的情况
      {
        $project: {
          total: {
            $sum: {
              $map: {
                input: "$historyList",
                as: "item",
                in: { $ifNull: ["$$item.price", 0] }
              }
            }
          }
        }
      }
    ]);

    // 聚合结果为数组,取第一个元素的total,无结果则返回0
    const total = aggregateResult.length > 0 ? aggregateResult[0].total : 0;

    res.status(200).json({
      code: 200,
      total: total
    });
  } catch (error) {
    return next(
      res.status(400).json({
        code: 400,
        msg: error.message,
      })
    );
  }
};

注意事项

  • 聚合查询中$lookup的from参数需对应MongoDB实际集合名,mongoose默认将模型名转为小写复数(如History对应histories)。
  • 需处理price为null或undefined的情况,避免计算结果为NaN。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:33:23