如何使用Mongoose计算用户的累计消费总额?
解决Mongoose关联文档累计消费计算的undefined问题
问题说明
现有两个Mongoose Schema:UserInfo包含用户名userName和关联History文档ID的数组historyList;History包含消费来源source、金额price、时间time字段。需要计算单个用户的累计消费总额,但当前代码循环获取price时返回undefined。
错误原因
- 未关联查询关联文档:原代码仅查询
UserInfo,historyList中仅存储History的ObjectId,而非完整文档,自然无法直接获取price属性。 - 语法与遍历错误:
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
相关产品推荐
相关产品推荐

